navigate site menu

Start learning with our library of video tutorials taught by experts. Get started

PHP with MySQL Beyond the Basics
Richard Downs

PHP with MySQL Beyond the Basics

with Kevin Skoglund

 


In PHP with MySQL Beyond the Basics, expert instructor Kevin Skoglund introduces powerful PHP programming techniques using object-oriented programming (OOP). Both novice and experienced PHP developers will benefit from the efficient, well-organized, reusable, and easy-to-understand code that OOP offers. Kevin shows how OOP techniques can streamline database queries, help manage sessions, and simplify user logins. While building a real-world web application, Kevin also includes practical advice on topics ranging from structuring code to logging user actions. Exercise files accompany the course.
Topics include:
  • Defining and using classes, methods, and attributes
  • Understanding class inheritance and access modifiers
  • Working with files and directories
  • Uploading files to a server via forms
  • Sending emails with PHP
  • Using pagination and View templates

show more

author
Kevin Skoglund
subject
Developer, Web, Databases, Programming Languages, Web Development
software
MySQL , PHP
level
Intermediate
duration
10h 27m
released
Mar 25, 2009

Share this course

Ready to join? get started


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



Introduction
Welcome
00:03Welcome to PHP with MySQL Beyond the Basics. My name is Kevin Skoglund and
00:07I run a web development company called Nova Fabrica that develops websites and
00:11database driven applications. This tutorial is the sequel to PHP with MySQL
00:16Essential Training and I'm going to assume that you either watch that training or
00:19that you already feel comfortable with the fundamentals of PHP, MySQL and how
00:23to use them together to create pages that interact with databases.
00:26In this tutorial, we're going to build on those essential training skills, to learn how
00:30to use PHP and MySQL in object oriented programming.
00:34Object oriented programming or OOP is a large and important subject that will
00:38get most of our attention. We'll also discover some intermediate PHP techniques
00:42like working with the server's file system, uploading files and sending emails.
00:46Now, it's not just theory either. In this tutorial, we'll build a complete PHP
00:50project using all of these techniques so that you can see the concepts in
00:53action and get some experience using them in real world situations.
00:57Now because you aren't a beginner anymore, there will be times when I ask you
01:00to do some basic coding on your own but it shouldn't be anything that you can't
01:03handle. That way, we'll be able to keep our focus on the techniques that are new.
01:06So, I'll assume that you already know the basics like making sure that
01:09an integer is actually an integer or checking an array is not empty before you try
01:14to loop through it.
01:15At the end of the tutorial, we'll have the skeleton of a working web
01:18application but one that still needs improvements and testing using skills
01:22that you already have. Enough with the introductions though. Let's get started
01:25learning more about PHP and MySQL.
Collapse this transcript
Using the exercise files
00:00If you are a monthly or an annual subscriber to lynda.com, you won't have the
00:03exercise files that accompany this tutorial, but you can follow along with me.
00:08Everything that's in the exercise files, we'll create during the tutorials.
00:11So as long as you continue to follow along, your files will exactly mirror what is
00:15in the exercise files. Remember that you can pause at the movie or rewind if
00:19you need more time to copy something down.
00:22If you are a premium member of the lynda.com Training Library or if you are
00:25watching this tutorial on a disk, you will have access to the exercise files
00:29that are going to be used throughout this title. The Exercise Files for this
00:32title are arranged by chapter and by movie and you can find the Exercise Files
00:37that correspond to the movie you are watching by first looking for the chapter
00:40number and then the movie number.
00:42In order to make use of the Exercise Files, you want to first make sure that
00:45you have PHP and MySQL successfully installed and there's an appendix at the end of
00:49the training if you need a refresher. Once you are confident that you have
00:52everything installed, then you will want to move the folder back to the
00:55Exercise Files into your site's directory.
00:57On a Macintosh that's going to be inside your Users directory and inside the
01:01Sites folder. If you are on Windows, you can move them into your Documents folder,
01:06or the folder where you would normally do your web development and then
01:08you can simply drag the file in. On my Mac, I'll Option+Drag to create a new copy.
01:14Once it's copied, if you rename the file so that you remove the chapter
01:18number and the movie number, then your files will be exactly the same as mine.
01:22In many of the chapters, we're going to be working with databases. In addition
01:26to the exercise files that you will drag in to your Sites directory and then
01:29rename, they will also be an SQL database file. This file can be loaded into
01:36MySQL to put your database into the same state as mine. If you don't already
01:40have a database to load the file into, you want to review the beginning of
01:43Chapter 5, where we first create our database and set up the necessary permissions.
01:47Once you do that, you can either load the file directly into MySQL by using a
01:51tool such as phpMyAdmin or by going to a command line and typing MySQL followed
02:00by the name of the user who is authorized to access the database,
02:04their password, the name of the database we want to use and then the less than sign
02:09followed by the path to the exercise file and you can either type out the full path
02:13or you may be able to drag it into the window. On a Mac, you are able to
02:17just drag it in there and it puts the whole path in there for you.
02:20Once you've located the file that you want to load into the database, simply
02:23hit Return and it will update the database with the instructions in that file.
02:27Once you have the same files and the same database, you will able to work right
02:31along with me. Don't forget you can also use the Exercise Files to check your work
02:34as you go along.
Collapse this transcript
1. Installation and Project Setup
PHP and MySQL installation
00:00Because this training tutorial is a continuation of PHP and MySQL Essential
00:04Training or because you already have previous experience, you should already
00:07have these two technologies installed on your machine. If not, we have provided
00:12an appendix that will help you to get them installed or you can refer back to
00:15the Essential Training.
00:16The one footnote I want to make to this though is just to make sure that
00:20you are using PHP 5 or later. PHP 4 has basically disappeared for all intents and
00:25purposes. It's no longer being developed. It's only being supported in the
00:29smallest way and it does not have all the features that we're going to be using
00:33for object oriented programming.
00:34So we really need to make sure that as a minimum, we have PHP 5 installed and
00:38we'll see how to do that when we set up the project in the next movie. You can
00:41also go to php.net and that will always let you know what the latest version is
00:46and give you links to get those downloaded.
Collapse this transcript
Project setup
00:00You should have PHP and MySQL installed at this point but there are couple of
00:04housekeeping things that I want us to take care of before we dive into PHP,
00:07just to make sure that we're working in the same sort of environment. Now
00:10if you remember, in PHP Essential Training, we created a folder that we called our
00:14sandbox and that's where you put all of these miscellaneous PHP exercise files
00:18that we were creating and working with. We'll do the same thing for this title.
00:21On a Mac, those are going to be inside your hard drive, inside the Users folder
00:25and inside your name. In my case, it is just Kevin and then inside that folder,
00:31there will be a folder called Sites. Now, on a PC, it will just be the root of
00:34your web server and that's where you will put all your files. On a Mac or a
00:38UNIX system, you are going to put those inside the User directory.
00:40You will see that I have php_sandbox here where I created those files before.
00:46I'm going to create a new folder here, just called btb for Beyond the Basics
00:52sandbox and that's where I'll put all these files. Now, there are two files
00:56that I want us to grab out of the php_ sandbox that we were working with before.
01:00The first of those is just basic.html. So, if I open that up in TextMate,
01:06you will see that it is just a real simple HTML template. Your text editor may even
01:10generate something like this for you but this is good to have on hand.
01:14I will drag that into btb_sandbox and the second one, if we go down is
01:19my_phpinfo.php. So, if we open that one up, you will see that it is just
01:25a real simple PHP info function that will give us the configuration information
01:30for PHP. It also has the nice side effect of letting us know that PHP is
01:35working, all right, because it's able to run this PHP code. Now, you will notice
01:39that there is the note there to remind us that we should never include this
01:42file on the production machine. We don't want the public to have the
01:45configuration info for our PHP. This is only for development.
01:48Now I'll take that file and I'll actually just drag that to my Desktop here and
01:52then go back up to drag it into btb_ sandbox. There we are. So now that I have
01:58those two files in there, I'm ready to locate them inside a web browser. So
02:01I'm going to go down and open up Firefox and the way we're going to locate it is
02:06localhost. That's our local machine. And then on a Mac, you are going to need
02:11to put a Tilde and your user name. For PC, you can leave that off, just localhost
02:16and then the slash, and then the folder name btb_sandbox and then
02:22my_phpinfo.php.
02:26Now if that comes up for you, then you have successfully located the file in
02:30the right place and PHP is running. If not, you will need to troubleshoot it
02:34and make sure that you have the files where they need to be, that your web
02:37server has started and that PHP is running okay. If we get here, we know
02:42we have got those things all working. The web server, PHP, and we have successfully
02:46found the right directory. Notice that it tells us at the top it's PHP Version
02:505.2.6 for me. You may have something different than that. That's fine as long
02:55as it is version 5 or later. Version 4 doesn't have all the features that
02:59we're going to be using. So you want to make sure that you are using version 5 or later.
03:03The last thing that I want in this to notice before we move on is this
03:07Configuration File (php.ini) Path and for me, it's in /etc. It may be
03:13something different for you. That's fine but this is the location of the
03:17configuration file for PHP. If we want to make changes to that file for any reason,
03:22to change the different options, that's where we're going to find the file
03:25and we can edit that with a basic text editor or through our command line
03:29tools and we saw how to do that previously, so I won't go over it again.
03:31I just wanted you to take note of where that file is in case you have forgotten
03:35because it is not often that we edit it. So now that we've successfully located that file,
03:39we're going to be creating files in our btb_sandbox where we can learn
03:44different PHP techniques and we'll get started with that in the next chapter.
Collapse this transcript
2. Intermediate PHP Techniques
Using variable variables
00:00Before we dive into object oriented programming and start working on a larger
00:04project, I want to take a little bit of time to visit some intermediate PHP
00:07techniques that may fill in some of the gaps in your knowledge or may prove
00:11useful to you as we keep working. The first one among these I want to look at is
00:14variable variables. That is where the variable name is determined by a
00:19variable. Let's take a look.
00:21So the first thing I'm going to do is I'm just going to open up baisc.html.
00:25I'm just going to do a Save As on this file and save it as variable_variables.php
00:35inside that btb_sandbox. Now I'll see the file is right here and that's where
00:39we'll be keeping all of the files that we're working with. Now I'll go ahead and
00:42just change the title to be Variable Variables, just for reference. Then we can
00:46put our PHP code here in this body block.
00:50So we have talked about variables in the past and you are familiar with using them.
00:53Something like $a = "hello" or we could have $hello = "Hello everyone."
01:03We know how to do echo $a or echo $hello. To make it nice and clean on the output,
01:12I'll go ahead and put some <br/> tags at the end of this and I'll do another one here.
01:18So let's go ahead and load it up in a web browser just as a simple starting point,
01:22localhost, there we are. btb_sandbox and then variable_variables.php. So there we are.
01:33Nothing that we don't already know how to do, but one of the
01:36questions that often comes up from students is what if we don't know
01:40the variable name that we want to use? What if it's dynamically computed?
01:43How do we go ahead and evaluate that name and have a dynamic variable name? So in other words,
01:49we would not know hello; instead we would have a string hello.
01:53We would want to use that string to return the value of the variable hello.
01:58Well it's really easy to do. All we have to do is echo $$a. So what this is
02:05going to do is it's going to take the value of $a and come up with the
02:09string hello and then use that with the second dollar sign to come up with
02:14the value of hello up here. It works exactly like you would think. Let me go ahead
02:18and just put in another <br/> tag down here and we can load that up. We can see
02:24that that's true.
02:25That's order is to being able to use dynamic variables. You may not have a good
02:29picture in your head of when this kind of technique might be useful.
02:32So I have made just a real simple example that I want to show you. I have created a file
02:36called seats.php. You don't need to copy it down but you can. It's real simple.
02:40It just simply takes a set of seats and let's imagine it's a classroom and
02:44the seats are labeled a, b, c, d and e. There is a different student sitting in
02:48each seat and we have assigned those to a variable.
02:50So then let's say maybe through a web form I'm able to get together an array of
02:56the seats that I want. So seat a, seat c and seat e, are the students that
03:00I want to reference or talk about or work with. Those can brought in as strings,
03:04stored in a database as strings, set in a web form of strings. Then what we'll do is
03:09we'll say well, for each student as the variable seat, just a foreach loop,
03:15take each one of those and do this dynamic variable retrieval,
03:18variable_variables.
03:19So in this case, you can see that it should return back to us the students
03:23sitting in the seat a, sitting in seat c and seat e. So if we save that,
03:28if we come back over here and let's just try it real quick, seats.php, you'll see
03:32that's exactly what we get.
03:34So it's a real simple example, but you can see how this information here, right,
03:38these items, could be pulled from a database or sent in a URL or web form
03:44and then used to reference something else. So that's the kind of case where to use it.
03:48Now there is one catch to this. There is one thing that makes it tricky. I want
03:52to make sure that I highlight it for you. That is, if you think about the
03:55syntax here, you have to wonder what would it do if we had something that was
04:00of this format? $$ and then the variable name and then the item that we want to
04:06reference inside an array. So in this case, we would be looking for the first
04:10item of an array. So with this syntax, would it mean to, number 1, get the
04:15first element of the array and then evaluate that answer dynamically?
04:20Or should it evaluate var dynamically and then look for the first element of that array?
04:26So it's not clear which one of these we should do first. This part is clear but
04:29then it's not clear for you should do the 1 before the dollar sign or
04:33the dollar sign before the 1. So in order to make this unambiguous and to make it clear,
04:37what we do is use the curly braces. So in the first case, we would put
04:43the curly braces around the $var and the 1. In the second case, we would just put it
04:49around the first variable, to let it know that it should pull that in first,
04:53then evaluate the first element from there.
04:57So it works a lot like parenthesis do in mathematical operations, telling us
05:01which one we want to do first. We're just using curly braces. That's only when
05:04we're really working with arrays that it becomes a problem. Most times it won't
05:07come up, but I just want to make sure that I at least gave you that footnote,
05:10so that you don't run into problems with it.
05:12That's all there is to using variable variables. Let's take a look in the next
05:15movie at some more functions that we can use this time working with arrays.
Collapse this transcript
Applying more array functions
00:00In this movie we're going to take a look at a couple of array functions that
00:02will allow us to put elements into and pull elements out of arrays, besides the
00:07techniques that we have already learned in the past. I think these are going to
00:10be really useful for you.
00:11The first thing I want to do is go and open up that basic.html file again, and
00:15I'm just going to do another Save As on it. This time we're just going to call
00:19it array_functions, and be sure to change it to .php.
00:24Then I'll change the title as well, Array Functions. Then we'll open up some
00:30php tags here and create ourselves a simple array. $numbers = array
00:37(1,2,3,4,5,6);. So it's just a real simple array.
00:42Now, you remember that instead of echoing back arrays, it's really useful if
00:46we can use print_r to be able to see them instead, and that just gives us some
00:50nice formatting for those.
00:52But then right after it, I'll do an echo of two br tags, just so that we can
00:58separate it from everything that's going to come after it.
01:01Now, the first technique I want to look at for pulling element out of an array
01:04is called Shift. So array_shift is the function name, and it will shift the
01:09first element out of an array and return it. So in the case of $a =
01:15array_shift($numbers); that I have there, you can almost imagine the first
01:19element being shifted out of the numbers array and being pushed and sent into
01:24that a. So it's shifting it from numbers into the variable that we have there.
01:30Now, we don't have to catch that, we could just run array_shift without taking
01:34that value and putting it anywhere and it will just continue to pull that first
01:37value out of it. That's what its doing really is pulling that first element
01:41out, whether we catch it in the variable or not is up to us. But we can go
01:44ahead and just do echo "a:" and then we'll put in the $a and put another <br/>
01:53tag at the end of it. Then let's go ahead, just for good measure, and let's
01:58take a look at what numbers is again.
02:00We will Save that. We'll go back into Firefox and we'll load up our sandbox
02:05page/array_functions.php. There we go. So you will see that all the elements
02:11have just simply shifted over, so that now the array is only 2,3,4,5,6.
02:17The 1 got pulled off and put into the variable of $a.
02:20Now, we can do the reverse of this as well, which is Unshift. So here I'm going
02:26to go ahead and just Paste it in there so you can see it. It's the same thing.
02:29What we're going to do is call array_ unshift($numbers); and provide it with the
02:34element that we want it to unshift to do the reverse. So in this case it will
02:39put it back or push it onto the front of it.
02:42Now, I'm also catching what that returns in the variable b. What it's going to
02:47return is the element count. It's going to let us know how many elements are in
02:51there altogether.
02:52This might be useful for you or not. Again, you don't have to catch that value
02:56in a variable if you don't want to, but we can do the same thing and take a
02:59look, just to see the difference. Sure enough, you will see that it has six
03:03elements in the array now. The first one is now first. It pushed it back onto
03:09the front of that.
03:09Now, when I was talking about these, I talked about unshifting as being pushing
03:14an element onto the front of it and shifting as popping an element out of it.
03:18It turns out that there are two more functions that we can use that are called
03:23Pop and Push. So I'm just going to put those down here.
03:26I have got an hr tag that I just dropped in at the top to just separate the
03:30two. Here is unshift up here at the top. Then I have got my new code, array_pop
03:34and array_push, and they work exactly the same, except that it pops the last
03:40element out of an array, not the first element, the last element, and returns
03:44it. Push does the same thing as unshift, but instead of doing it to the
03:48beginning of the array, it pushes the element onto the end of an array.
03:52We can see this, if we save our new file and we reload it in the browser. We'll
03:56now see, in this example, we pulled the 1 out and replaced it with first. Then
04:03first still persists all the way through here, it never gets pulled out. But
04:06the last element here, which was 6, gets removed and assigned to a. Then we put
04:13in the word last, we'll push that onto the end. So Shift and Unshift at the
04:17beginning, Push and Pop at the end. So those are going to be the four that are
04:21going to allow us to put things into our array at the beginning and the end.
04:25Now, we know we also have ways of assigning a value directly to a certain
04:29position, we saw those in the Essential Training, but this will allow us to say
04:32whatever that value is at the end, not only do I want to retrieve it, but I
04:36want to take it out of the array at the same time. That's the thing that
04:40we couldn't do before. It both gives us the value and takes it out of the array at
04:45the same time. So those are going to be really useful for you, I think, when
04:48working with arrays.
04:50Now, I want to encourage you to take time to go through the PHP website,
04:54php.net, and look at the other functions that are available. array_shift is
04:58right here, but you will see there are a lot of array functions here that
05:01you can use, and it's worth seeing how arrays can be powerful for you, because
05:06there are so many functions and so many different ways you can use them.
05:09I am not going to try and cover them all, because a lot of them are for rare
05:11cases, but I think that you might find array_flip is something that helps you
05:16out of a jam that you are in, or array_ keys gives you what you are looking for.
05:20So take some time and explore all of these functions, build yourself your own
05:24page, start playing with them, and see what they can do for you.
05:27But we're going to move on and we're going to take a look at dates and times
05:30in the next movie.
Collapse this transcript
Building dates and times: Epoch/Unix
00:00One of the areas that perplexes a lot of beginning developers is working with
00:04dates and times. That's partly because there are a lot of different ways to do
00:09it and there are a lot of restrictions that depend on what kind of operating
00:12system you have, what kind of database you are using, and things like that that
00:16just make it into a quagmire that's hard to wade through.
00:19So I'm going to give you some of the basics, some of the essential concepts
00:22behind it, and then you will have to take a look at your system and see what
00:26works for you and do some research on ways to work around it, but this will at
00:30least give you the fundamentals.
00:32The first thing that we need to talk about is going to be Epoch time or the
00:36Unix timestamp. These are the same things, and if time sets the computer
00:40epoch_began. So basically that's the time that Unix is going to use for its
00:45timestamp. Essentially it's the number of seconds that have elapsed since
00:49January 1, 1970 at midnight. That is the beginning of the computer epoch
00:55according to the Unix timestamp.
00:57Since Unix is a file system, it must have seem like common sense to the people
01:01developing it that a file could not be created before January 1, 1970. The
01:07problem comes in when we start using these dates for things besides just files
01:10that are being created on the computer and start using them to keep track of
01:13birthdays and other calculations, then we might have dates that go into the past.
01:18Now, if we have a 32 bit system, we're able to use dates from December 1902 to
01:23January 2037. 1970+67 years to get to January 2037, or 67 years in the past to
01:33get to December 1902. We do that by having a negative number. So we can count
01:38time forwards and backwards in negative numbers.
01:40But that also limits us. We still can't talk about some birthdays.
01:44We can't talk about dates that happened in history. We can't talk about future, social
01:49security payments, and things like that that might happen past 2037. So that's
01:53still a pretty limited range.
01:55So ultimately, what I think is going to happen is most systems will end up
01:58going to a 64 bit system of counting, because that will last for billions of
02:02years and that will take care of all of our needs, but we haven't done that yet.
02:06So on your system, you may be limited to 1902-2037, and if you are on a Windows
02:12machine or maybe some of the older Linux distributions, even dates prior to
02:161970 might give you a problem. I think I ran into that with the IIS database.
02:21It had problems with dates before 1970, and that's because Windows does.
02:25If you ran into one of those problems, what are you going to do? Well, there
02:27are many choices and it depends on your needs. You can store the date as a
02:31string, you can store the year separately from the date, or you could read up
02:35on one of the many hacks that are out there on ways to get around it. The
02:38php.net website is full of a lot of those.
02:41But for the purposes of this tutorial I don't want to focus on how you are
02:44going to work around the limitations of the computer you are working with,
02:47because you may get a shiny new compute tomorrow that handles all of it fine,
02:51instead I want to talk about the fundamental principles that we're going to be
02:53working with to create a Unix timestamp.
02:56There are three ways that I want to look at to do that. The first is just time.
02:59time with no arguments, just have the parenthesis and that will
03:04return the current time. Remember that's the number of seconds since 1970.
03:10So that's the Unix timestamp.
03:11Now, the second is that we can make time, mktime and we just need to provide
03:17it the number of hours, minutes, seconds, and then month, day, and year.
03:22It will come back to us with a Unix timestamp, the number of seconds since 1970.
03:27Now, notice the order there, it gets a little confusing for some people. It has
03:30the time first, hour, minute, second, and then it has month, day, year, which
03:35is sort of the American way, instead of day, month, year, like they do in other
03:38countries. So they are not in sort of ascending order or anything like that,
03:43it's a little bit of a jumble, but that's the order it's going to be. An hour,
03:45minute, second, month, day, year.
03:47The last is string to time, strtotime, and then we provide any string to that
03:54function and it will return a Unix timestamp to us, doing the best it can to
03:58generate that timestamp based on whatever is in that string. We'll take a look
04:02at that, it's a pretty neat little function.
04:04So I'm going to open back up array_ functions, and I'm just going to do a Save
04:07As on that file, and I'm going to call this date_time_unix.php, just to
04:13remember, because we're going to take a look at some other date, time features later.
04:15I'm going to take out all of this and I'm going to call it Dates and
04:20Times: Unix.
04:22Now, the first way that we're going to make Unix time we said was just with the
04:27simple Time command. So we'll do that with just echo time;. We'll save that,
04:32and let's open that up in our browser and see what we get back. So we'll just
04:35open up a new window and we'll go back to our sandbox/date_time_unix.php.
04:44There we go. That's how many seconds have elapsed. If we reload it, we can see all
04:48the seconds as they continue to count.
04:51Now, we'll learn how to format that into something that looks nicer a little
04:54later. What we're interested right now is just getting that Unix timestamp,
04:59because once we have a Unix timestamp, we can start to compare different
05:03timestamps. We can see when something happened 5 minutes ago, 10 minutes ago,
05:06by comparing the current timestamp with the timestamp that we have stored,
05:10let's say, in a database or in a file or something like that.
05:13The second way we saw that we could make a timestamp is with mktime, and
05:19you will remember that I told you that we have to provide the number of arguments here.
05:22We can do those as variables or just simply integers. So the first of
05:26those is going to be the hour, let's say 2, and the minute 30, and the seconds
05:33we'll make 45. Then we need to put in the month and the date and the year, and
05:40I'll put in 2009. Semicolon there and let's, just for good measure, let's put
05:46in <br/> tag at the end of this just so it will be on a new line. Let's reload it.
05:52There we go.
05:53So now you see the difference between the current time and the number of
05:57seconds there, and this date in the future for 2:30:45 on October 1, 2009.
06:04We can actually subtract the two and find out how many seconds there are in
06:08between and then convert that to a number of days and so on.
06:11Now, one note is that if you give something invalid to mktime, it will return false.
06:16So if you try to tell it the date was February 30, that's an invalid
06:21date and it would return false.
06:23Now, there is also another way that we can check whether dates are true that's
06:26worth mentioning, and that is with checkdate.
06:30If we say, for example, echo checkdate (12, 31, 2000), and then we'll ask it to
06:39return 'true', if that's a true date, or 'false', if it's not. We can do the
06:46same thing again. Let's go ahead and put our brs in here, just to make it nice and clean,
06:51but this time let's ask it for February 31. Let's see whether that's a date.
06:56So if we come back and we reload those pages, you will see that the first one
06:59is a date and the second one is not a date. So checkdate is also a helpful way
07:03to check whether a date is there or not.
07:05Last of all, I want us to take a look at that really cool function, the
07:09strtotime. So let's say $unix_ timestamp = strtotime, and then we can put in
07:19a string that designates whatever time we would like. Now, this is the cool
07:23part. For example, let's try "now". Then I'm going to need to echo back that
07:28$unix_timestamp if I set that as a value. I'll append a br after it.
07:34Let's load that up and see what we have got. So there we are. Notice the times
07:38are the same at the top and the bottom. time("now"), there is no difference
07:42whatsoever. I can also put in something like "15 September 2004", and then come
07:50back. There is the date stamp for that. I could also do "September 15 2004",
07:56and you will see I get the same date stamp. So it's able to interpret these
08:02different ones.
08:03Let's try "+1 day". That's tomorrow, or we can say something like "last Monday".
08:11So there are a lot of these different things that we can do, that
08:16we can pass in as a string and it's able to interpret what we mean. Now, it isn't
08:20always 100% successful, you will have to play around and try it out a little bit,
08:24but it does a pretty good job of parsing it out and figuring out what you mean and
08:28turning that into a Unix timestamp. So keep that in your back pocket
08:31because that's a really useful tool.
08:33Now that we know how to make Unix timestamps, in the next movie we'll talk
08:37about how to make those into something that's human readable, how to go from a
08:41timestamp back to something that we can display, that looks nice as output on our screen.
Collapse this transcript
Formatting dates and times: Strings and SQL
00:00In this movie, we're going to continue looking at dates and times.
00:03In the last movie we saw how to build a Unix timestamp, and in this movie I want us to take
00:07a look at how we can format that Unix timestamp.
00:09There are two functions that are going to allow us to do that. The first
00:12function is date and the second is strf time. Now, you can either pronounce
00:18that string for time, string format time, but the idea is that we're taking a
00:23timestamp and turning it into a string. So in both cases we're going to be
00:27formatting a Unix timestamp into something that's human-readable, like November
00:3113, 2005, instead of however many seconds it has been since 1970.
00:36That's not very user-friendly.
00:38You will see that each of these functions takes a timestamp as a second
00:41argument. That timestamp is just a simple Unix timestamp, we can take any
00:45timestamp we have created and drop it into that second argument. It's the
00:48format that's the tricky part and that we're going to have to learn more about.
00:51In fact, the functions may look identical but what differentiates them is the
00:55format. Each function has its own format rules. Let's take a look at date first.
01:00The easiest way to show you the formatting options for date is to take a look
01:03at the http://www.php.net page for date. Go to http://www.php.net and do a
01:07search for date and you will get this page. Here are the different formats for
01:11the output string. Scroll down.
01:13Notice the format characters over here, d, D, j, and so on, and it tells you
01:20what each code does. So, for example, d is the day of the month, two digits
01:24with leading zeros, such as 01 to 31. You will notice that j is also the day of
01:31the month, but without leading zeros, 1 to 31. D is a textual representation of a day,
01:37the three letters, Monday through Sunday, so Wed for Wednesday, for example.
01:41Now, we can scroll down a bit further on the page to see how these strings are
01:45used. The format is a simple string but with the format characters as
01:49placeholders for each part of the date. When the date function is called,
01:53it will replace the format code placeholders with the actual data.
01:56So for example, this format string here will return the line right above it.
02:02Monday 8th of August 2005 and then the time.
02:06Now, in this example they are not passing in a timestamp, so it defaults to the
02:08current time. But in the example below that, you can see that they do pass in
02:13the timestamp as a second argument. They build the timestamp using mktime and
02:16then pass it in.
02:17Notice also that the format code that they are using in that second one is just
02:21simply an L, and that's it. If we go and look at L, you will see what it does
02:24is it returns the day of the week. So this will tell you what day of the week
02:29July 1t 2000 is. That's a nice little trick. Not only are we able to format the
02:34date in something human-readable, we're actually able to find out some
02:37information about the calendar as well.
02:39Now personally, I don't use date and I would recommend that you also use string
02:43for time instead. The reason why I like it better is that its part of the Unix
02:47Open Standard and it's used by many programming languages, besides PHP, and has
02:51support for formatting dates in foreign languages as well. So let's take a look
02:55at the string for time format codes to see how they are different from the ones for date.
02:58So for example, if we look here at %d, you will see that there is a % in front
03:02to it, first of all. The % helps make it clear that this is a format code. So
03:07all the string for time ones are going to be proceeded by % sign before the
03:10code. So essentially %d does the same thing that d did in the date function.
03:16But now take a look at %D. You will see that this is different. Instead of
03:21being the three-letter code for the day of the week, it's going to be a
03:24shortcut for the month, day, and year as numbers with slashes in between them.
03:29Instead, if we look at %a up here, you will see that that is the abbreviated
03:33weekday name. So that's how we get that same functionality we had before.
03:36So some of them are going to be the same. %m for example down here, the month
03:41as a decimal number. That's the same. But %M and other ones like that are not.
03:45So there is a lot of differences. So you really have to learn each set of code
03:48separately, and that's why I think you ought to pick one and stick with it, and
03:51I recommend you go with the string for time (strftime).
03:53Now obviously, this list here of codes on the string for time is a
03:57comprehensive list, and you may want to copy down the ones that you are going
04:00to use most often and make yourself a little cheat sheet. But you will also get
04:03familiar pretty quickly with them and you will be able to remember the ones
04:06when you need it.
04:07So let's try this out now. I have still got my old window open for
04:11date_time_unix. Let's go ahead and do File > Save As on that, and we'll call
04:17this one instead date_time_format.php, and I'll just change it up here to say Formatting,
04:23and then we'll go ahead and clear up all the PHP we had there so we can start fresh.
04:29So the first thing I'll do is I'll just build a real simple timestamp with the
04:32current time. And we know how to do that with just time. Then let's make
04:36ourselves echo back the result of strftime, and we'll say, "The date today is"
04:44and let's put in our format code, so %m. So the % sign lets it know it's a code
04:49for strftime, and then the m tells it that it will be the numbers for the
04:53month, and then we'll have %d/%y. Then last of all we need to pass in of course
05:00our timestamp.
05:02Let's go back over to our browser and try that out. Instead of loading up Unix,
05:07I load up format.php. There you go. So today is November 1 2008. Now, today is
05:13not actually November 1 for me. Instead I set my system clock to that time so
05:17that I could show you something.
05:18Now, earlier I pointed out the reasons why I like strftime better than date.
05:22There is one feature that date has that strftime doesn't. Date has options for
05:26leaving off the leading zeros before a month or a day number. Notice here I
05:31have got the 01. That's the leading zero that I'm talking about in front of it.
05:34We kept the option to leave that off in date and it could just simply be
05:3811/1/08. The same thing would be true if we were talking about January, string
05:43for time would print as 01, whereas in date we have the option of leaving the
05:48leading zero off.
05:49A lot of times we're going to want to get rid of those leading zeros. So I'm
05:52going to show you how you can do that by writing yourself a helper function.
05:55It's a little bit of a hack but it is effective.
05:57So what we'll do here is we'll just take this line and we'll copy it down here,
06:03and instead of just sending in the formatting, we're going to put an asterisk
06:06in front of each of these two. Those are the two places where a zero may show
06:11up. So we're sort of marking the position where we want to watch for a zero,
06:15and we're doing that with this asterisk. Now, you can use any character you want.
06:18I picked the asterisk because it's something that I don't use very often
06:22when I'm formatting this kind of date, but you could easily use a different character
06:25if you needed the asterisk for another reason.
06:28So now let's write ourselves a helper function, function strip_zeros_from_date,
06:36and then we'll pass in $marked_string=, and there we go, we'll pass in a empty
06:44string by default. The first step is that we're going to remove the marked
06:49zeros. So $no_zeros will be equal to str _replace, and we'll use string replace
06:59(str_replace) to look for every occurrence of an asterisk with a zero, and if
07:03we find it, eliminate both, get them both out of there. Then we'll just need to
07:08pass in the marked_string so it knows what to search through.
07:11Then once we do that, the last step is we'll remove any remaining marks,
07:19because we don't want to have to deal with a case where we have something like
07:22December, which would not have a leading zero, and so we would still have that
07:25asterisk sitting there because it didn't get removed.
07:27So we'll then do another step, $ cleaned_string =, and we'll do another
07:32str_replace. But this time we're going to be looking for any asterisk that's
07:36still left around and we'll replace that with nothing, and we'll do that to our
07:40no_zeros string. Finally, return back that cleaned value.
07:48So there we go. Now we have a function that should work for us. Let's just move
07:51this strftime down below the function so that it's defined. We'll just put it
07:56around the whole thing. There we go. I'll save it, and let's come back over.
08:01Let's try it out.
08:02There we are. It didn't put a br tag in there but you can see this one does
08:05have the 01. This one did remove the 01.
08:08So most of my PHP projects I go ahead and just put it in a function like this
08:13that will help me to use strftime and to be able to get rid of those zeros, and
08:17I think it might be helpful to you too.
08:18The very last thing I want to show you here is that I can also format strings
08:22suitable for storage in MySQL. A lot of people wonder how you do this
08:26conversion. You don't want to just pass in a Unix timestamp to MySQL; you want
08:30to format it to something that MySQL can understand. Luckily it's very, very easy to do.
08:36Let's do echo "<hr />" just to make a nice break there, and then we'll do a new
08:44$dt = time;. That will be dt for date time.
08:48Then what we want to get is $mysql_ datetime, and the way we're going to do that
08:53is using that strftime function and we're going to put in the following
08:57formatting code. %Y, that's the year with all four digits, and then %m, %d,
09:05then a space, %H for the hour, %M for the minute, and %S for the second. There
09:14we go, and then of course we'll want to pass in that time we were just working
09:18with. So we could pass in any timestamp, and we're going to have it output with
09:21this formatting. That will go into this mysql_datetime. Of course, if we want
09:25to see the results of that, then we'll just need to do an echo on it. There we go.
09:29So we'll come back and there we are. That's the format that MySQL understands.
09:36So go ahead and write down those formatting codes. Make sure that you keep them
09:40handy for working with MySQL. But you also may want to just make a copy of this
09:45here, just to show you what the result should be, in case you end up using date
09:49or some other system, whatever, this is the format that MySQL wants for date,
09:53time fields. Now, if is the date field, it will just be the date part of that,
09:56but this is the format it's going to use.
09:58So now that we have learned to work with and format the dates and times,
10:01we're ready to move on. In the next movie we're going to look at server and request variables.
Collapse this transcript
Setting server and request variables
00:00In this movie we're going to take a lok at how we can retrieve and work with
00:03server and request variables. Now, we have already seen some superglobals that
00:07we can work with. We saw Get, Post, Cookie, and Session. Well, there is one
00:11other one that I want to introduce you to, and that is Server. That's where
00:15we're going to be able to find all of these server and request variables, is
00:19inside the superglobal for Server.
00:21So what we're going to do is ask that superglobal to return a value to us for
00:26various information, like the server name or the remote IP address that made
00:31the request for this webpage. A lot of times we'll want to keep track of that
00:35to know where the request came from, what the user's IP address is. We can do
00:39that using the Server superglobal.
00:41Let's try it out and see some of the things we can ask it for. I'm going to
00:45open up basic.html and I'm just going to do a Save As on it, and we'll call it
00:51server_variables.php, and put it in our btb_sandbox, and Server Variables.
01:00Now, the first two that we'll take a look at will just be simply looking at
01:04information about the server that we're on. We can ask for our server's name,
01:09for our server's address, and for its port. Let's try those out and see what
01:13we get back and think about how you might use that information.
01:16We will open up Firefox, and instead of going to date_time, we're now going to
01:21go to server_variables.php. So there is the information that I have for my server.
01:28Now, once you install this on a production machine, probably your server name
01:31will change, the port, the address, those things will all change. Because I'm
01:34using local host, it goes ahead and resolves the server name to being local
01:38host and my IP address is just simply listed as one.
01:40There are a few other things we can ask for. We can ask it for the document
01:46root on our server, where all our files are located. We can also ask it for
01:51details about the page that we're working with. So here are some page details,
01:55PHP_SELF. That's a very useful way to find out what page this is.
02:00server_variables page, or SCRIPT_ FILENAME, we can also pull that back.
02:05Let's take a look at those.
02:06I will save that file. Let's just reload over here, save the file. There we go.
02:13Reload it. So you will see my DOCUMENT_ ROOT, it tells me where the documents
02:16are located. Then the Page details, it tells me the path to get to the page
02:21that it's actually executing. Then the SCRIPT_FILENAME, you will notice, gives
02:24me the same thing, but it gives me from the root of the user's directory.
02:29PHP_SELF is what's being typed into the URL bar that's up here. The other one
02:35is actually the path on the file system. That's the SCRIPT_FILENAME. So notice
02:39the difference between those two and make sure you use the right one in each context.
02:42If we want to redirect someone to a URL or something, we would use PHP_SELF.
02:47But if we're trying to locate a file to include or require into our script,
02:51then we might want to use something like SCRIPT_FILENAME or our DOCUMENT_ROOT,
02:55for example.
02:56Now, notice that DOCUMENT_ROOT here is actually not my user directory. That's
02:59because of the way that Apache is set up on a Mac system, so that my actual
03:03root of all of my web server is going to be in this
03:07/Library/WebServer/Documents folder, not in each user folder. That's why I have
03:11to use this Tilde in my user name.
03:14Then perhaps most interesting to us, we can find out information about the
03:18request that comes in. So we'll switch back over here and we can get details
03:23with Request. We can get the remote address that's asking for it. The
03:27REMOTE_PORT, the URI that they ask for, the QUERY_STRING, if they ask for
03:31anything after the URL, the time it was made, the REFERER. That's who referred
03:36them to our website and that's really useful for keeping track of links and
03:39finding out did someone get to us by clicking on a link on Google, for example,
03:43or did they click on a link at Yahoo! and that's how they found us. Then an
03:46USER_AGENT, which is what browser they are using. So those are great for
03:49statistics and server tracking and that kind of thing. So I'll save that.
03:53We will come back and we'll just do a reload. Now, of course my remote address,
03:57since I'm doing it from the same server, is just going be 1, but if we were to
04:00put this up on a server somewhere, then it would obviously pick up my IP address.
04:05Now, you notice that the QUERY_STRING is blank, let's go ahead and just put in
04:08something here. Let's say q=1&n=2. You will notice that now it pulls in the
04:18elements in that query string and we're able to then work with those and parse
04:22those if we need to.
04:23Now, we also have access to those through the get superglobal, those will be
04:27put there for us already, and that's basically what's its doing is taking query
04:30string and parsing it for us. But if we need a direct access to it or
04:34if we wanted to store in the database and keep track of it or something,
04:37we could also do that by just looking at the query string.
04:39Now, there are a lot of other server variables. I think these are the most useful ones.
04:43If you want to go to the php.net website, it's a little tricky to find,
04:47but php.net/manual/en/reserved. variables.server.php and that will give you
04:57all of those server variables that you could have access to and you can look
05:00and see if there are any others that sound interesting to you,
05:02anything you want to play with, but I really think that the main ones are the ones that
05:06we just took a look at.
05:07There is one more thing that I want to caution you about. There is also a
05:09superglobal called Request. Don't use Request. When you are trying to get those
05:14request variables, you want to get them from the Server superglobal. Request is
05:19a superglobal that basically just contains all of those Post and Get values
05:23that we already have access to through Post and Get, so it's a little bit
05:27redundant. If you want to find out the remote address of the request,
05:31the REQUEST_URI, do that through the Server variable, not through the Request superglobal.
Collapse this transcript
Establishing global and static variable scope
00:00Now that you are not a beginner anymore, we need to talk about variable scope a
00:03little bit further, and specifically talk about global and static variables and
00:07what those can mean for us and do for us. We saw global briefly in the
00:11Essential Training, but I want to go into it again here and expand on it a bit
00:15to make sure that you understand what's going on.
00:16I am going to open up that basic.html again and just do another Save As on it,
00:21and we'll call this one variable_scope.php. Variable Scope.
00:36We talked about local and global variables in the previous training.
00:39Just to refresh your memory, variables that are declared inside the PHP document are in
00:44the global scope. So if I just start declaring something like var = 1,
00:49that is in the global scope.
00:51Variables declared inside a function have a local scope. So if I say, for
00:56example, function test1, and we'll go ahead and just declare a variable inside
01:03there, var = 2, and that has a local scope, its local to that function. We can
01:10test this out by just having it echo out those two values for us. So var, and
01:15let's have it do br for us. We'll take the same line. We'll just put it down
01:21here. But we'll also need to, of course, call the function, test1.
01:29So if we try that out in our browser and let's go to variable_scope. It figured
01:38up the PHP for me, .php, there it goes. You notice the first time the value is
01:432 and second time its 1. So even though we set the variable to 1,
01:48then we defined our function, which doesn't actually do anything, doesn't execute anything.
01:52Then we execute the function here, which does set variable equal to 2,
01:56and we echo it out. That's first two we're seeing, but then when it comes
02:00back and it echoes it again, it is echoing the variable that's in the global
02:04scope. So study that a little bit and make sure you understand the difference
02:07between local and global.
02:09Now, we saw though in the Essential Training that we could also do it another
02:14way, so that we could have access to that global value inside our local
02:19function. I'll just take the same thing again and we'll come down here. Of
02:25course, I'll need to make it test2 so that we don't conflict with the
02:28previously defined function. But this time the one difference I'm going to do
02:32is I'm going to call global and var.
02:36So what that does is it says, hey, you know that var and the global scope>
02:41That's what I mean when I talk about var. All references from var, from here on
02:44out, I'm talking about that thing. It's like importing it into the local scope,
02:50but it retains it. So it just pulls it in so that we can work with it as a
02:53reference almost.
02:54So let's try that. Let's go back and let's set up our page again.
02:57Now you notice that var did change the second time. So this assignment here, var 2, did
03:03take place to only the global scope. It brought in the global to the local,
03:08made the assignment, and that assignment stuck around.
03:11So again, study those two examples and make sure you understand what global is
03:15and why we use that global declaration before our variable to let it know that
03:20we want to use the global value.
03:21Now, the main reason I wanted to go over this and make sure that you understand
03:25it, it's not just so that you are comfortable in using it, but also because it
03:28leads us into talking about static variables. A static variable is a local
03:33variable to a function, but with one important difference. It doesn't lose its
03:37value when the function is done.
03:39So look back at test1, typically calling test1 will always yield the same
03:44value, 2, if we increment it, it's always going to revert back.
03:48To show you what I mean, I'm going to copy this whole thing again, and this
03:53time I'll make it test3. There we go. Then I'll take out the global line for
03:58now. Once this whole thing is done, then let's do, var++. So that's just going
04:04to increment var. That's a shorthand to say var=var+1. So it's going to
04:11increment it one time.
04:12Now let's try running this one and see what happens. So I'm going to run it and
04:17its 2 and 1, just like it was before. Let's try running it a second time and a
04:23third time here. So I'm going to call it three times. Every time it's equal to
04:292. This incrementation that we did, it increments. So var is set to 2, it
04:36outputs 2, and then var is set to 3. The next time we call it, var = 2, var
04:41outputs, var gets incremented, it gets set to 3.
04:44But if we declare static in front of it, static var with a default value of 2,
04:52then when we call it every time, it increments, 2, 3, 4.
04:58So notice it's still a local value. It didn't affect one. That's on our global
05:05scope, it's still in the local scope, but it's a static value now that keeps
05:10its value and sticks around every time the function is called. So it works like
05:14a counter variable inside this function.
05:17Now, while we won't use static variables very often, it's a good tool to know
05:20about, but even more importantly, I want you to understand it so that you won't
05:23be confused when we talk about a slightly different application of the word
05:27static when we get to object oriented programming a little later.
05:31There is going to be another use of the word static and this is going to be
05:33helpful to have this as a foundation so that we can talk about that. A lot of
05:37beginning programmers get the two confused and aren't sure what the difference
05:40between them is, but that won't happen for us.
Collapse this transcript
Making a reference assignment
00:00In this movie we're going to talk about references, specifically reference
00:03assignment. References are going to allow variables to refer to the same
00:08content as other variables.
00:10Open up basic.html and just do a Save As on that and let's save this as
00:16references.php, Reference Assignment. So if we have, for example, a variable a
00:30which is equal to 1 and then we have a variable b which we set equal to a. Now
00:35if we set b equal to something else, like 2, then if we echo back those values
00:43for a and b, we can guess what they are going to be. It should return, returns
00:481/2. Let's try it out and see.
00:51I open up Firefox and let's bring up references. There it is, 1 and 2, just
00:59like we would expect. But what if instead of doing that, we instead used a
01:04reference and the way we use references is to put an ampersand after the equal
01:09sign. And that does what is called Reference Assignment.
01:13So now instead of b being simply equal to the value of a, b references the same
01:21thing as a. So the bit of computer memory that's holding a's value, b is now
01:26pointing at that same thing. The easiest way to think about it is it's like
01:30when you make an alias in the finder in a Mac or when you use a shortcut on a
01:34PC and you have a folder and you can make a reference on alias or shortcut that
01:40allows you to get to that same folder. That's what we're doing here.
01:43We're making it alias to it.
01:45So now what happens when we set these values. So let's save it. I'll erase
01:50those because we don't know what it returns yet and we'll hit Reload and we see
01:54that it returns 2 and 2. Now the reason why is because b points to a, so when
01:58you change the value of b, it changes a at the same time because they point at
02:03the same thing. They are equivalent, b and a. So make sure that you understand
02:08that that's what a reference is.
02:10Now why use references, why not just use a or make a copy of a? One of the main
02:15reasons is that we can delete our reference b and a will still be there, just
02:19like if we deleted a shortcut from my Desktop, it does mean that the folder
02:23that was there is completely gone, we have just erased that shortcut.
02:27So a lot of times we want to be able to have that kind of disposable link there
02:30that we can break and destroy but still leave the underlying values intact.
02:36When we decide that we're ready to unset it, then we can just simply use
02:39unset($b) and that will unset b for us. Then let's just echo those values back
02:46just to see what they are equal to again and you will see that now a is still
02:49equal to 2 but b is equal to nothing.
02:52So that's the basic concept behind references. We're going to look in the next
02:57few movies at other ways that we can make use of them.
Collapse this transcript
Using references as function arguments
00:00In the last movie we learned about references and how we can have one variable
00:04that references the same value that another variable references. It works like
00:08an alias. Well, now I want us to look at how we can pass in references to
00:12functions. So the argument itself that's being passed in is a reference.
00:17Let me show you what I mean.
00:18Here I'm in my references file that I was just working on. I'm just going to do
00:23a quick Save As on that and we'll just call this one references_args and that
00:29will help us keep them separate. Then we'll make the name of it, References as
00:34Function Arguments and we'll take everything we're working on and just take it
00:39out of there and let's try a real simple function here. Let's so just say
00:43function, we'll call it ref_test and we'll pass in a variable. In there,
00:49we're just going to do a real simple transformation to that variable just so that
00:53we can see whether the value gets affected. You can just do +1 or something like
00:56that. I'm going to do x 2.
00:59Now we know that if I have a value like a and then I pass in ref_test a and
01:07then echo back the value of a. Stop and look at that for a second and tell me
01:11what do you think the value of a will be. Remember what we know about local and
01:15global variables. Hopefully, you are able to tell that a starts out as 10, the
01:20value of a gets passed into this function ref_test as an argument. It gets
01:25multiplied by 2, but then nothing ever happens because this is a local scope,
01:29it's the local value and a is a global value.
01:33So when we come back and we echo a, a has been unchanged. So let's just
01:36demonstrate that just to make sure that we're clear on that. It's the basic
01:40things we're talking about before with local ad global values.
01:43So I'll open up Firefox and instead of references, I'll just ask it for
01:47references_args. There we are, value is still 10, not 20 but 10. So it did not
01:53change because this is the local scope.
01:55We saw in the last movie how we used ampersand with the equal sign for
01:59Reference Assignment. We're going to use that ampersand again here, but this
02:03time we're going to put it in front of the argument. So it will be like that.
02:05It will be ref_test(&$var).
02:10So what we're saying here now is when something comes in, don't take its value,
02:16make a reference to that value. So therefore, a and var are going to point to
02:22the same thing. Now let's watch what effect that has. I'll save this. We'll go
02:27back and we'll reload the page and now notice it's equal to 20. Because var is
02:34pointing at that same thing as a, it's like an alias now.
02:38So in the same way that a shortcut or an alias on your computer that's, let's
02:41say, an alias for a folder, if you drop a file into that folder, it both goes
02:46into the alias and into the actual folder that exists in both places because
02:50they point to the same thing.
02:52So that's what's happening here, it's affecting that same value because they
02:55are both pointing at the same thing. Now if you stop and think about it for a
02:58second, this is exactly the same as if we had taken the & out and just simply
03:04called global $a and then simple made this a as well, right. Let me change this
03:12one too. Those have the same effect. Let's just try it, all right, exact same
03:18effect. In fact, we can actually not even pass in a value here if we're working
03:22with global, all right.
03:24So there is a little bit of difference in that, we don't have to pass in a
03:27value when we use global, when we're using the args version, we do, and we have
03:33the ability to name it something else. We don't have to have the same variable
03:37name as we had when we use global. So we're able to rename it in the local
03:41context but have it still reference the same thing.
03:44So it's going to be a little bit up to you to decide whether you want to bring
03:47in a global value or whether you want to simply work with it as a reference.
03:51They are going to achieve a lot of the same things. It's just going to be
03:54syntactically a little bit different. So make sure you understand both of them
03:59and then you will be able to use whichever one feels right in each situation.
04:02In the next movie, let's look at how we can have functions return values that are references.
Collapse this transcript
Using references as function return values
00:00In this movie, we're going to continue to talk about references. We have seen
00:03what references are and we have seen how to pass them in as arguments to a
00:06function. In this movie I want a take a look at how we can return references as
00:11return values out of a function.
00:13To start with, I'm going to create a new file. I'm just going to use my
00:15references_args file and I'll just do a Save As on that and we'll call this
00:21References as Function Return Values. Now I'll go ahead and get rid of all of
00:33the functions I had there and I'll write in a new function and it's going to be
00:38function ref_return and I'm not going to pass in any arguments to it, but
00:44instead I'm going to have a global value that I'll pull in, global a.
00:48I will use a and just do a simple transformation on it so we can see that it
00:53has changed, and last of all return that value. Then I'll go ahead and set a
01:00equal to 10 and if I have b equal to ref_return, right, then that should take
01:09whatever return value came back from the reference return, and it should put it
01:14into b. So in order to test this out, let's echo those out so we can see them
01:20and I'm just going to do a real simple echo on those and let's see what they
01:24are equal to.
01:25So I'll save that, come back to the web browser and we'll just do returns.php.
01:31So they are both equal to 20. It starts out a is equal to 10, then we run this
01:37function which brings in a as a global, changes its value. It's a global so
01:42we're affecting that global value of a and then it returns it to b so b is also
01:46equal to 20, fair enough.
01:48But now notice what happens if we say well, b is equal to 30, and let's take
01:53that same line and let's test that out. Now, b equals 30 and a equals 20,
02:00right? we're not using any kinds of references. So b is just a separate
02:04variable and when we change its value, it doesn't affect a, right? Because
02:07we're not using the references.
02:08Now we talked about Reference Assignment before and we learned how to simply
02:11use the & after an = for a reference value and that we used it before we would
02:18say that, b references a. Let's save this and let's just try it here and see
02:23what happens.
02:25Nothing, nothing changed, it gave us the same value back, right? Because it's
02:30returning a value to us. Now it says return a here, but it's not returning the
02:35actual variable a. It's not returning a reference to a, it's returning the
02:40value, the same way as when we passed in arguments and we said that we were
02:44going to have the first argument be passed in be a. Without that Reference
02:49Assignment, we were passing in the value of a which was 10.
02:53So in this case, what we're returning is the value here, not a, just be clear
02:58on that, it's returning the value. The number 20 is being returned and that is
03:03being set up as a reference, b is referencing 20, which really is kind of
03:07meaningless for it to reference 20, right? It's equal to 20; it's the same thing.
03:10So in order for this to return a reference, we need to put another & here at
03:16the beginning of the function name. So that's where it's going to go, it's
03:20going to let us know that we're returning, it doesn't go down here, it goes up
03:23at the beginning of the function name and it says return a reference value.
03:26Whatever return value comes out of here, will be a reference.
03:30That means that what's being returned out of here as a reference, so that's
03:33returning actually a is being returned, but if we don't have this one then b is
03:38still just being set to the value of a, right? So we need both of them. It's
03:42important to have both so that the reference is being sent out of the function
03:47as a reference and it's being set to b as a reference. You have to have that
03:52handshake between the two. Otherwise it won't work.
03:55So now let's try it and let's reload it and we see that now in the second line,
04:00a and b are both equal to 30 because when I set b equal to 30 here, it also
04:05changes a at the same time, because they are a reference and we know how
04:08references work, we have seen that.
04:09So once again, if you need to play with it a little bit, try taking out the &
04:13here and see what you get and try taking out the & here and see what you get.
04:17You will see that it doesn't work in either case. It's because we're passing
04:20out a reference and then we're setting b to that reference. It's two steps to
04:25that process. So make sure you are clear on that.
04:28Before you move on, I just want to give you another example. I'm just going to
04:31skip down here and I'll put another function which I have called increment and
04:35this one instead using a global variable is going to use static variable, which
04:38is going to start out by initializing to 0 and then we'll increment it by 1 and
04:43return that value. It makes sense, its called increment. But it's going to
04:46return a reference to that static variable.
04:49So if we catch that value of increment in a, then the variable will increment.
04:54a will now be a reference to that increment. So therefore, if we call it a
04:59second time, just on its own, like that, what will be the value of a be? a is
05:04still pointing to the static variable. When we call the function again, even
05:09though it's not doing any assignment, it increments that static variable. So a
05:12still points to it. Even more interesting is that we can increment it this way,
05:17because a points to the same thing as increment. So it's once again
05:22incrementing that static variable. So either one works.
05:26We will do the same thing one more time, increment, and then last of all, just
05:31so we can prove to ourselves that this has been working, let's do an increment.
05:35So last of all, just so we can prove to ourselves that this has been working,
05:37let's echo up the value just so we can see what it is.
05:40So I'll save this and let's go back and let's reload it and you will see that a
05:44is equal to 4. The first time it increments it, then it increments it again,
05:48then again, and then again, four times. The static variable in there is just
05:53getting incremented and we can do it either way, because we have made a
05:56reference to a value inside this function.
05:59These reference techniques that we have been learning will become more useful
06:02later when we start working with object oriented programming and with
06:05databases. We'll talk more about references after we talk about objects.
06:09Let's begin our discussion of object oriented programming in the next chapter.
Collapse this transcript
3. Introduction to Object-Oriented Programming (OOP)
Introducing the concept and basics of OOP
00:00I would like to start out this chapter on object oriented programming or OOP by
00:05first talking about the concept and the basics of object oriented programming.
00:09PHP is the scripting language or may also be also called a procedural language.
00:14It's not really a true object oriented language. Instead, it's a scripting
00:17language that has some object oriented features built into it. PHP 4.0 first
00:22gave a few limited object oriented features. It really wasn't until version 5.0
00:27that we had full object oriented support in PHP.
00:30Do you need object oriented programming? If scripting and procedures are all
00:34you want PHP to do, then you probably don't need OOP. In fact, it might even be
00:38a bad choice. After all, if it ain't broke, don't fix it! But if you are
00:41pushing PHP harder than that and asking it to do a lot of complex work, then
00:45OOP may be exactly what you need.
00:48Don't let any preconceived notions about what a scripting language can or
00:51should do, limit you from the possibilities of object oriented programming in PHP,
00:55and most of all, don't be afraid of it. Here is my rule of thumb.
00:59I always say that for a simple site, object oriented programming adds unnecessary complexity,
01:03but for a complex site, object oriented programming adds necessary simplicity.
01:08Now the next question you may be asking yourself is what are objects? Well,
01:14in the simplest way, objects are simply grouping code together by a common theme.
01:19So if you think back to some of the work that we did in the Essential Training,
01:22we had a lot of different functions related to working with forms. We could
01:26have rolled all of those up into a form object and then our code would stay
01:31grouped together and we would have been able to find all of those form
01:34functions in our form object.
01:37Now there is a more complex way that we can use them as well, which is not just
01:40to group them together, but actually to abstract the structures in our code
01:44into objects. In other words, to make our software objects seem very similar to
01:49real world objects. And this makes sense because a lot of what we're doing on
01:53the web, we think of as objects. We have a page, a page could be an object
01:58or a form, a form could be an object.
02:00Those could be physical objects in the real world in the same way or we could
02:04have customers, students, shopping carts. Those are all objects and we can hold
02:10them in our head and think about them as objects. Objects have not only
02:14functions that allow them to do things, but they have attributes as well.
02:19So we would have a student who has a first name and a last name or a shopping
02:23cart that has a total quantity in it. Those are attributes of each of those
02:27objects, and it's easy for us to think about because we're used to thinking of
02:30objects in our head in that sort of way.
02:32It will become clearer what objects are as we start working with them, but let's
02:36first take a look at some typical PHP code that we might have in a project
02:40we're working on. We might have a student whose first name is John, his last
02:44name is Doe, we might have another student Mary and Smith. Then if we wanted to
02:48find out a student's full name, we would have a function where we could pass in
02:51those two values, Mary and Smith, and it would return Mary Smith to us with the
02:56space in between them. We have been doing that kind of thing before, but we can
02:59already see how this is going to start to break down if we start having a lot
03:02more complexity.
03:03This is just where we're dealing with two students and a simple function to put
03:07their name together. What if we had a lot of functionality then?
03:10What if we wanted to know the courses that the student is in? I can have a simple array
03:15that defines what each of those is, but what if each of those has some
03:18complexity to it? What if I don't want to just have student one's course be English
03:22but the English class that starts at 1 o'clock on a Wednesday. Then we start
03:26having a lot more complexity there and objects are going to serve us well
03:30because they are going to allow us to pull all that complexity into a very
03:34simple data structure that we can work with.
03:37So why are objects going to be useful for us in programming? They are going to
03:40give us better code organization and maintainability. If we group all of our
03:44functions and variables related to forms into something that's a form object,
03:49then we'll know right where to go when we need to make a change to the forms.
03:53If we roll all of the codes related to a student together into a single student
03:58object, then when we want to make a change to the way that that code works,
04:02we know right where to go. We go straight to that object and we make the change.
04:05It also adds clarity and reduces complexity and that's because we're able to
04:10think about these complex bits of data, all of the functions related to
04:14students, all of those attributes, however much complexity we give to it,
04:17we can think of as a student and student has all of that functionality built into it.
04:24So it becomes very clear, we have a student and a student object. It can be
04:27asked questions, it can be asked to do things, it can be asked to return data
04:30to us, but without us having to navigate all that complexity each time.
04:34The simple rules that we put into objects can actually allow for complex
04:38interactions. Let's imagine for a moment that we have a classroom and we have a student.
04:43We can issue a simple statement like put the student in the classroom and
04:46the objects themselves can have complexity built into them that says, well, before
04:51you do that, check and make sure that the class is not full, make sure that the
04:54student doesn't have a class that conflicts with the time of this class,
04:57for example. Then once it puts the student in there, it can update the total class count
05:01and the class can keep track of how many students are in it.
05:04So all that complexity can be built in and all we have to do is say, put the
05:08student in the class and those simple rules will all kick in. And because of that
05:11it's going to emphasis the data over the procedure. The procedure is going
05:15to be already preprogrammed for us inside these objects and we can really work
05:19on just the data and how the data interacts.
05:22Objects are also going to give us code modularity. Because the code is going to
05:25be broken into discrete sections, we can go in and work on one section at a
05:30time and not worry about hurting something else. This is great if we have a
05:33team of developers, because different developers are going to be working on
05:35different sets of objects and not interfere with each other; the code will be
05:39separated. And last of all is code reusability. If we write a complex shopping
05:44cart object, then all of that functionality is there when we take that same
05:48shopping cart object and use it for another client.
05:51And last of all, objects are well suited for databases. If we have a table of
05:56students, then each of those students can be an object. If we have a table of
06:00classrooms, then each of those classrooms can be an object. If we have a table
06:04of cars, each car can be an object and so on. So object oriented programming is
06:09going to a nice fit for working with databases.
06:11Now I think that's enough background on the concepts and advantages of using
06:15objects. I think it will start to make a little more sense as we start to
06:18actually code and that's what we're going to do in the next movie where
06:20we start defining classes.
Collapse this transcript
Defining classes
00:00Now that we have gone over the fundamentals of objects, it's time to see how
00:04we can actually define an object, and we do that by defining an Object class. So
00:09what we're going to be working here are classes, and we're going to be seeing
00:11in this movie how to define a class.
00:13To start with, I'm just going to open up TextMate to a new file and I'll just
00:18do a Save on that file into my sandbox and I'm just going to call it
00:22class_example.php. I'm not going to have any HTML in it; I'm just going to
00:28start out with some PHP.
00:29Now every class definition begins with the keyword Class and then right after
00:34that is the class name. So it could be for example, Student. Now, it's worth
00:39noting that it's in CamelCase, which means uppercase for the first letter, and
00:44then in the other words would also be capitalized. So for example, Portfolios
00:49let's say it would be a StudentPortfolio and you see the CamelCase there.
00:53That's because of the hump that's created by the capital P that's there.
00:57So I'm going to create my first class. I'm just going to call it Person, and
01:00then we're going to have a pair of curly braces, and everything that's inside
01:03those curly braces is going to be the definition of the class. Principally,
01:07that's going to be its variables and its methods.
01:09Now sometimes you will see this written like this. That's fine. It has the
01:13exact same effect. White space doesn't really make a difference in PHP.
01:17I'm going to tend to write them like that. So whichever way you prefer to have your
01:20curly braces. That's all there is to defining a class.
01:23Now it's not a very exiting class, there is nothing in it, but that is now a
01:27class. Whenever we create a class, PHP keeps track of the fact that it has been
01:31created. It's similar to how required ones keeps track of all the files that
01:35have already been required. Remember there is an array that we can look at to see that.
01:39We can have classes = get_declared_ classes and that's a special function that
01:47will grab all the classes that have been declared and put them in our variable
01:51and then we can do foreach ($classes as $class). We'll just do a simple for
01:58each loop through them to see them, echo $class and then we'll just put a
02:04little br tag at the end. There we go.
02:07So now if we just try running this simple script, it will define the class.
02:11There is nothing in it but it will still define it in anyway. We'll then add it
02:14to the declared classes, and we can pull that value back and output each of our classes. Let's just try that.
02:19So I'll go into Firefox, and we're going to be in our sandbox again, but this
02:24time class_example.php. There is a list of all the declared classes.
02:30Now you see there is a whole lot of them. A lot of these are already declared by PHP
02:34for us, but if we do a search here, actually down at the very bottom is Person.
02:38That's the one that we did. So PHP defines all these other classes for us, and
02:42then Person is the one that we defined.
02:45Now there is another way that we can do this besides listing them all out,
02:48let's take all of this code real quick, and we'll just comment it out.
02:55Instead, let's ask if class exists and then in quotes we'll put Person. Then if
03:05it exists then echo That class has been defined and we'll put a br tag after
03:14it, and if not, we'll say else echo Class not defined! we'll put our br tag again.
03:24So that's just going to do a quick check to see has the class been defined or
03:31not, does the class exist? So we'll save that and let's just try reloading that
03:35page. We'll see how that works. There we go. So that class has been defined.
03:44If we change it to something like Animal and then we go back to Firefox,
03:48and we reload the page, we'll see Class not defined.
03:51So that's one good way to find out if a class exists or not. So even though,
03:55we have done a very unexciting class at this point, we already see that it's been
03:59created and we can find out a little bit of basic information about it. In the
04:02next movie, let's take a look at how we can add some functionality to our class.
Collapse this transcript
Defining class methods
00:00In the last movie, we saw how easy it is to create an object class, but our
00:04class wasn't very exiting. What we need to do is add some more functionality to it
00:08and that's what we're going to do in this movie.
00:09Now, classes can contain methods. These are the same things as functions but
00:13generally they are called functions when they are on their own and methods when
00:17they are inside of a class. Now I may slip up from time to time and call it a
00:20function but keep that clear. If it's on its own, it's a function;
00:23if it's inside a class, it's a method. That's the standard convention of
00:27object oriented programming.
00:28Now, I want you to go ahead and do a Save As on this file that we're working with,
00:30because I want you to still have this code down here for your reference,
00:35but I wanted to get it out of our way as we continue working. So let's do a
00:38Save As and we'll just call this class_example2.
00:44Then we'll go ahead and get rid of all of this. We'll leave our class
00:47definition because we're going to continue to work with that and improve it.
00:50So I'll save this file and now we're going to add our first method to it. Now,
00:54even though object-oriented programming says we should call it a method,
00:56we actually use the keyword function still to define it, just like we normally do.
01:01So let's make one just called say_hello, and this is just going to echo back,
01:06Hello from inside a class. Everything is still the same as we normally do with
01:14the function. It's just been rolled up inside of this class, so that it's now
01:18one of the methods of the Person class. So say_hello is a method of the Person class.
01:23Now just like we did with seeing what classes are defined, we can also find out
01:27what methods are defined. So $methods = get_class_methods ('Person') and then,
01:37we can do the same kind of loop that we did before foreach ($methods as
01:43$method) and then we'll just echo $method and we'll put a br tag.
01:52Let's go ahead and save this and try it out. I'll save it and let's open up
01:55Firefox and reload, class_example2, say_ hello. There are the class methods that
02:03belong to person say_hello, and we also can do the same kind of thing that
02:06we did before, or we can actually query if (method_exists and it will return true
02:13or false for whether or not the method exists and then we can put in the object
02:17name, Person, and then the method name. So say_hello.
02:23So we'll check to see whether it exists or not, return true or false, and then
02:26we can just give a simple echo Method does exist. Let's go ahead and keep it
02:34nice and friendly. We're putting a br tag in there, else, and then we'll just
02:40do echo "Method does not exist." Let's save that and try it out. Put our br tag
02:50at the end. So there it is, Method does exist.
02:58Now if we try something else like say _hello_to_me and then we go back to
03:05Firefox, reload it, Method does not exist. So we can check to see whether
03:10methods exist the same way that we can check to see whether classes exist, and
03:13we can get a list of all those methods if we want. But we still haven't seen
03:16how to actually use this functionality.
03:18We have been able to put in functionality to our class, but we haven't been
03:22able to use it yet. In order to do that, we're going to need to talk about how
03:25to instantiate a class and we're going to do that in the next movie.
Collapse this transcript
Instantiating a class
00:00In the last couple of movies, we created a class and gave it some very simple
00:03functionality, but we haven't seen how to actually use our class or its
00:07functionality. In order to do that, we're going to need to talk about how to
00:10instantiate a class. Now that may be a word that's not very familiar to you,
00:14if you haven't worked with object oriented programming before.
00:16What we're going to be doing is creating an instance of the class and that's
00:20why we say instantiating. It's a fancy way of saying we're creating an
00:24instance of the class. Think of a class as a pad of stationary or let's say
00:31maybe one of those While You Were Out pads where you take messages for
00:34someone who has gone, and it has a space for the first name and the last name
00:37and the person who called, and their phone number, the time they called, all of that.
00:41So think about a little pad like that that's sort of preprinted with all
00:44this information.
00:45That's going to be our class is that pad of paper. What we're going to do with
00:49each instance is tear off one of those sheets and fill it out. Each instance is
00:53like another page. So every instance is different from each other because they
00:57have been filled out with different information, but they fundamentally are the
01:00same. They are all a 'While You Were Out' note, and that's different from let's
01:04say a doctor's prescription pad. That's a different class and it has different
01:08fill in the blanks on it, for filling out a prescription, and each of those
01:12will be very similar to each other, they will all be of the same class, but
01:15they will be different from our 'While You Were Out' notes.
01:17So what we're going to be working on now is how to sort of tear off one of
01:20those pages of stationary and fill it out with some more specific information.
01:24Let's see how to do that. I'm going to take my class_example file. I'm just
01:27going to do another Save As on it, just that we still have a record of that
01:31work that we were just doing. I'm going to hit class_example3, and I'm just
01:35going to get rid of all of this at the bottom, but I'm going to leave the class
01:39that we still have been working with at the top as we continue to expand that.
01:42Now, in order to instantiate a class, what we do is we say New and then Person
01:48with parenthesis. That creates a new person. Now, it creates it and then it
01:53does nothing with it. It just creates it and it's not accessible to us anymore.
01:57So we need to assign it to a variable so that we can work with it. So $person =
02:02new Person object. So take the class Person, tear me off one of those sheets,
02:07and I'm going to fill it out.
02:08Now we don't have a place for first name or last name or anything like that
02:11yet, we'll get to that later. But what we have done is simply pulled off one of
02:15those sheets from our memo-pad and assigned it to Person. Now we can have
02:19another one, it could be $person2 = new Person.
02:25Now, these are two different instances of the same class, Person. Make sure
02:31that you understand that, this is two different occurrences of the person. So
02:35I'm a person, you are a person, Steve is a person, Bob is a person, right?
02:39All of us have some things in common. We all have a first name and a last name,
02:43we all have two arms and two legs, and so on. So we're all of the same class, but
02:47each one of us is a different instance, a different occurrence, and that's what
02:51we have got going on here.
02:53Now we can find out what class an instance belongs to. For example, we can say
02:56echo get_class and then ($person) and let's go ahead, and like we always do,
03:03just put a nice br tag at the end of that and that will return what class this
03:08instance of person is.
03:10Obviously, we have named it Person, so it's very obvious. But if we called it
03:13Bob, or if we called it Student, then it might not be clear that it's a person
03:18that we're talking about. It's a helpful way to make sure that we know what
03:21class we're talking about, and there is another way that we can do it as a
03:24Boolean, just like we have been doing the others.
03:25We can say if (is_a, and then we can put in, ($person, and 'Person')). So if
03:33person is a person, it kind of reads weird and backwards, but what we're saying
03:38is if this instance, this person variable is of the class Person, then return
03:45true or false, and we can say echo "Yup, it's a Person", or else, echo "Not a
04:00person". So that's a way we can test. We can find out what class it is or
04:07we can test whether it is or not.
04:09Let's just try those two out real quick. We'll go into Firefox and we'll bring
04:12up class_example3. So it comes back and tells us it's of the class Person, and
04:18then it says Yup, it's a person. Now, if we were to make it a different class
04:22and say is that of the class animal, even though animal is not defined? Come
04:26back here and no, it says not a person, but obviously it's returning a Boolean false.
04:31So now you know how to create an instance, and once we have an instance, then
04:36we can activate the functionality that's inside of that object. So the way
04:41we do that, the way we can call our functions in there. It's a method. The method
04:46say_hello is we simply say Person, and then an arrow. I'm going to always call
04:53that an arrow, but it's the minus sign and the greater than and then say_hello
04:58with the parentheses after it, just like we do it with our functions. It's
05:02still a function. We still need to have these parentheses to indicate it.
05:05All we're doing is saying look inside the person and in there, find the
05:10function called say_hello, so that arrow notation, we're going to get very
05:13familiar with. You will see that I don't need to do any kind of echo before it
05:17because the echo is already in my function. So let's just try that out real
05:20quick. Go back to Firefox, and we'll just reload the page, Hello from inside a class.
05:26So now we have created a class, we've put a function in it, we've made an
05:30instance of the class, and we've called the functionality that's inside of it
05:35by using that arrow notation. So at its most fundamental, that's all there is
05:39to actually using classes.
05:41With just this much knowledge, you already could wrap up a lot of your
05:45functions, put them into classes and make them class methods, and call them
05:49using the notation that we have here. Now earlier, we talked about references
05:53and how references would play an important part of working with objects, and in
05:57the next movie, we're going to see how that's the case.
Collapse this transcript
Referencing an instance
00:00We talked about reference assignment back in Chapter 2 but now I want to talk
00:03about how references apply to objects. Now the good news is that you actually
00:08don't have to do anything. You just need to understand what's going on.
00:12Reference assignment is automatic for objects in PHP 5. Now that wasn't true
00:16back in PHP 4. Let's first take a look at why it's true, and why we would want
00:21this function to be automatic.
00:22Let's imagine that we have a new person. So we have created a new person,
00:26we have assigned it to a variable. Then let's say somewhere else in our code later on,
00:29we decide to say well, the customer is equal to that person.
00:32Now if we don't use reference assignment, then that would mean we would need to make a copy
00:37of the value just like we did back when we had A and B, and then we said B = A.
00:42If we don't use the reference assignment, they don't point to the same thing,
00:45it actually duplicates the value, but in this case, the value is an object, and
00:50an object contains a lot of code. Now so far, a person object has been very
00:55simple. We just have that say_hello method, but even that would get copied, and
00:59if we had 20, 30, 40 different methods inside the Person class, then all of
01:05those would get ported when we made the copy. So each and everyone would have
01:09that same functionality.
01:10If you go back to the metaphor that we're using for tearing off a sheet of a
01:14stationary or a notepad, then we would basically be making another page,
01:19another sheet of paper, and copying all the information down on it too, and
01:23then we would have two pieces of paper that are identical. What we actually
01:26want is a reference to the same one. So because objects can be very large and
01:31take up a lot of memory, it's going to be more efficient for PHP to not make
01:34copy of the whole object, but to make a reference assignment instead.
01:38Now, it's no problem if you still include that reference assignment, and you go
01:42ahead and put that em percent there. In fact, it's common practice and we'll be
01:46doing it a lot throughout this tutorial, so don't be surprised if you see it
01:49there. If nothing else, it demonstrates what the programmer's intent is, even
01:54if the PHP engine would have already done the same thing for you.
01:57In case you are wondering, we'll take a little later about how you would
01:59actually copy objects if you wanted to copy them. But there is another
02:03important way that we reference the instances of a class. Now notice that I
02:06said instances, it only applies to instances and that's with the
02:10Pseudo-variable: this. Let's take a look at it.
02:14So here I'm in the class_example we're just working on. I'm just going to do a
02:17Save As and we'll make this class_ example4_PHP and just like before, I'm going
02:23to get rid of everything that was down here and we're going to continue to work
02:27on our class. The pseudo-variable: this with a dollar sign in front of it can
02:31be used as a reference to refer to the calling object when you want to call a
02:35method from within an object.
02:37Let me show you what I mean. So right now, we have echo "Hello from inside a
02:42class." Well, what if we wanted to actually have the class name? So instead of,
02:45Hello from inside a class, let's change it to say From inside the class, and
02:50then we'll have it put in the class name here. So I'll put in two periods to
02:55append this together, and then we'll use our get_class method that we saw
02:59earlier. How do we talk about the class of this instance, and the way we do it
03:04is with this. There is a dollar sign in front of it, and then this. What we
03:08mean is this instance.
03:11Now right now, we're talking about the class and the class is the same for
03:14every instance. That's not important. What's important here is that we're
03:17asking it to use this as a reference for the instance and get_class is
03:22something we've applied to instances earlier.
03:24So let's just try that out real quick. We're going to go ahead and need to
03:27create a new instance, person = new Person and then we'll tell that person that
03:34it should call the say_hello method. So let's try that out.
03:39We will go back to Firefox and this time it will be example number 4, Hello
03:47from inside the classPerson. Now, I forgot my space in there, but you get the
03:50idea. Here we go. So that's how we reference an instance. So let's do another
03:55one real quick. We'll just type function and then hello, and then let's have it
04:02call this and say_hello.
04:05So now, we have got one method that's calling another method.
04:10So what do you think will happen if you come down here and simply call our hello method in addition?
04:15Let's go back and try it. You can see it does the same thing.
04:20So this, with the dollar sign in front of it, is the way that we're going to refer
04:23to the instance and call different aspects of that instance from inside the
04:28class, only inside the class is where we're going to do that.
04:31In the next movie, we'll take a look at how we can start to define some class
04:35properties, so that we can continue to add complexity to our class.
Collapse this transcript
Defining class properties
00:00Now, in addition to methods, classes can also have their own variables that
00:04belong only to the class, and these are also called properties or sometimes
00:08attributes. Attributes of the class. Or instance variables. And we now know what
00:13an instance is, so it make sense that it's a variable inside an instance.
00:16It's an instance variable.
00:18So you hear me as all three of those words interchangeably. I may say
00:21properties, attributes or instance variables. And in every case, what I mean
00:24are the variables that belong inside a class.
00:27Let's take a look at how we can define these. So I'm inside the class_ example4
00:31file I was working on and I'm just going to go ahead and do a Save As on that,
00:34just so that we can start the new file and not worry about losing our old work.
00:38So I'm going to declare some variables here at the top.
00:42Now, normally you would think we would just declare variable like first_name.
00:47That's the way we're used to just being able to define a variable name. But the
00:50one difference is that inside a class we have to put var in front of it.
00:55Now, in the global scope var is optional. We can just have the dollar sign and
00:59it will know that we mean var, but inside the class, var is something that
01:03we definitely need to let it know this is a variable, and so just var first_name
01:08and semicolon and it's not equal to anything. It just being created. It just
01:12exist, it's there and it's waiting for us.
01:16So let's go ahead and create another one, we'll just make it var last_name.
01:21Now, we can assign values so for example, let say we have var arm_count = 2.
01:28That sets the default value to arm_ count. It's the same way that we have been
01:32making assignments to variable in the past. But we still need to var in front of it.
01:36Let's do var leg_count = 2. So by default every instance of the person_class
01:44that we create will have two arms and two legs. It will have a first name and
01:47last name but they won't be equal to anything.
01:50So let's try this out. Go ahead and take away the say_hello message that we had,
01:54and let instead try to access these attributes. So echo person and then
02:03their arm_count with nothing after it. And that will reference the attribute arm_count.
02:10Now notice that there is not a dollar sign here. That would make it a dynamic
02:14variable. like we talked about back in Chapter 2 a variable, variable name. All
02:19we need is the arrow notation and then the name of the attribute.
02:24Now. if it had parenthesis after it, it would go looking for a function,
02:28otherwise it goes looking for a variable and that's how it knows the
02:32difference. It doesn't need the dollar sign anymore to know which one it is. It
02:36uses the presence or absence of those parenthesis to know.
02:38So let's try this out. Let's go back into Firefox and let's open up
02:43class_example5 and there it is 2.
02:45So return back to arm_count was 2. Now, we can also set values this way, let's
02:51say for example, person arm_count it's going to be equal to 3, and while we're at it,
02:58let's go ahead and say person first_ name it's going to be equal to Lucy. So
03:05I don't think we need to actually echo those back and try them out.
03:08I think you understand what's going on there.
03:10Now, this is where our OOP gets its power, because now we can have different
03:14instances that are different. So we can have new_person = new Person and that
03:21is going to have a default arm_count of 2, even though our other instance has a
03:26default arm_count of 3.
03:27Let's go ahead and say new_person first_ name equals Ethel. And then if we echo
03:36back the person first_name and we'll put a br tag at the end of that and then
03:44we do the same thing for the new_ person, we'll able to see that those are
03:49different. Let's go ahead and take a look at that in Firefox, and sure enough
03:53there is Lucy and then Ethel. I don't have a br tag here to keep that nice and
03:58clean. I'll go ahead and add it now.
04:00So now we can see the difference between different instances and how each of
04:04these objects can be different. Let's go ahead and add a little more complexity
04:07to this. Let's take our hello method out of here. We don't need that anymore.
04:12And instead we'll make a new function and we're going to call this one
04:15full_name. We saw this as an example earlier. This is a really common use of
04:19how we would use object oriented programming, and for this we're going to
04:23return back this first_name and space and this last_name. So now if we drop
04:35back down here, and we say that the new person's last_name should be Mertz and
04:46the regular persons last_name should be Ricardo.
04:54Now, instead of asking for person first_name, let's ask it for person
04:58full_name and we'll need those parenthesis after it. Those parenthesis,
05:02remember, are important to let it know that we're calling a function and not an
05:08attribute called full_name. So let's save that, let's go back over to Firefox,
05:13and let's reload it. There we are.
05:15So now you can see, how we can start having attributes and we can start
05:19grabbing those attributes and working with them. Now, we're working with them
05:22in a really simple way right here. We're just taking a first_name and a
05:25last_name but we could have a lot of complexity there where we could grab
05:29different pieces, check different aspects of a class, even look at other
05:33classes to find out information about them, and in the end, turn something
05:37back, and then every instance can return something different because it has a
05:41different attributes to it.
05:42The last thing I want to leave you with is that attributes work just like the
05:46methods do and we can actually find out some information about whether they
05:50exist or not, whether they have been defined. So for example, I can say vars
05:54equal get_class_vars and person and that will give me all of the class vars
06:02that are defined inside person, and just like before we can do for each vars as
06:08var and the var has a value, if we want to see what that is, we can actually
06:13take a look at the value, and then echo var and value. There we go.
06:29Let's go back over to Firefox and try that out, I'll just save it Firefox and
06:33let's reload, so there they are, we see what's defined and we also have the
06:38Boolean expression same as we did before. This time we can say echo
06:43property_exists and in the person_class do we have the property first_ name and
06:52I'll just do a real simple operator here, we saw how to do this before, this is
06:57nice let me have something really simple. false. So let's try that out.
07:01We go back to Firefox, reload the page and true, it does exist. So that's how
07:06we can also have the Boolean expression.
07:07So now we have covered the fundamentals of object oriented programming. That's
07:11really the core what we need to know that we can define a class, we can put in
07:15attributes, we can give it methods, we can create instances of that class and
07:20then we can start putting values in and out asking for methods to do there
07:24thing and that's really all there is to it.
07:27Now, there are lot more and interesting things that we can do besides just
07:30these fundamentals, and that's exactly what we're going to look at in the next chapter.
Collapse this transcript
4. OOP in Practice
Understanding class inheritance
00:00In the last chapter, we looked at the fundamentals of object oriented
00:03programming and specifically, we learned how to add attributes and methods to
00:07class definitions.
00:08Now, I want to add a little more complexity to our classes and start looking at
00:11more of the features of object oriented programming as we start to put into
00:15practice. And I want to kick it off with a discussion of class inheritance.
00:18Now, the idea of inheritance is essential to object oriented programming and
00:22basically it's this. We can define one class and then we can define another
00:27class that inherits its behavior from the first class and when I say it
00:31inherits behavior that means it inherits its attributes and its methods.
00:36Let's take a look at how we can do that.
00:37So I'm just going to go down to open up my text editor. I'll do New File and
00:42I'm just going to do a quick save on this. We'll put it in the sandbox and
00:45I'm going to call inheritance. There we go. And I'll just start out my PHP tags.
00:54Now we have already seen how to define the class. So let's just do that real
00:57quick. Let's say class Car, and we'll say that our car has attribute called
01:05wheels and it's going to be equal to 4 by default. Another variables it's going
01:10to equal to doors. We'll make that equal to 4 by default, and then let's say a
01:15function and we'll just make a silly function here, we call it wheelsdoors. And
01:21that will return this wheels, right we know how to do that, plus this and arrow
01:30doors. So it's going to add those two together and return it. So like I said
01:33it's a silly function but it will at least make the point for us. And then
01:37let's make another class, class CompactCar.
01:41Now, we could just go ahead and define CompactCar, right and we could tell it
01:46how many wheels and how many doors it has. But we can instead use inheritance
01:50and say well, actually this is going to extends car. class car extends car. So
01:57if we extend this class then it inherits, all of its behavior from car. Okay,
02:03let's just give this a try, without doing anything else, let's now say all
02:06right we have car1 and that's going to be equal to a new car, and then I'll go
02:11ahead and have car2 and make that equal to a new CompactCar.
02:15So now I have one each of these classes. So let's say echo car1 and let's find
02:24out its number of wheels, and we'll add our br tag at the end, and it will look
02:29nice and pretty. And I'm just going to copy that line.
02:32We are going to also ask for its doors and we're going to ask for wheelsdoors
02:38with the parenthesis right because this is a method that we're calling, and
02:41then let's see another echo br and then I'm just going to copy all of that,
02:49second time and this time it's going to be for car2.
02:51So let's take a look now. If we open that up in Firefox, we'll go back to our
02:57sandbox which is local host and then the tilde Kevin if you are on a Mac
03:03otherwise just btb_sandbox and then let me put this in inheritance.php. What
03:12happens? Notice that both of them return the same values, right? Wheels 4,
03:19doors 4, wheels+doors = 8.
03:21CompactCar though it didn't have any definition. It got all of that from car.
03:26That's what inheritance is. And if we were to go back and change it, so that
03:30the doors on car now are 2, and we save it, reload it, and they change for both
03:35as well. At the time that we create the class in our PHP page, it inherits its
03:42behavior from the other one.
03:42Now, of course we could change these values in each instance, right. We could
03:48go ahead and say well, actually both are going to have 4 but then we're going
03:51to stop right here and tell car1 that it actually has two doors. That's still
03:55not going to change CompactCar. CompactCar is still going to have four doors
03:58because it's inheriting the default behavior in the class, not the instance. So
04:03it doesn't matter how we push and pull on different instances of it, right
04:07because we can have a red car, and a blue car and a green car and we can define
04:10those all after we create this class.
04:13The important part is that CompactCar takes this definition and just imports it
04:19down here into its own body. That's what the extends does. Now, one of the nice
04:24features about inheritance is that we have the ability to override those
04:28characteristic that are in the above one.
04:30So we can say well you know what, everything that's in this CompactCar class
04:34should be the same, except the door should be equal to 2. And now it will
04:38inherit everything that's above but doors will be equal to 2 not 4, all right,
04:44we can try that real quick just to see it. So there is the difference.
04:47So it overrides the inheritance and we can do that for anything. I'll just take
04:52function wheelsdoors real quick and just copy it down here. So, we'll have that
04:56in there as well and let's say +100. So now we go back and we run it, you'll
05:02see that it overrides that inherited method.
05:05So those are the two fundamental concepts about inheritance that we need to
05:08know is that, one that we can inherit all of those attributes and methods and
05:12two, that we have the ability to override them, if we don't want to use them.
05:17The last thing, I want to do before we leave inheritance though is to show you
05:20a couple of other methods that you can use, and I'm just going to paste them in
05:23here. You'll see I'm using get_parent_ class and I'm using is_subclass_of. Those
05:28are two methods that are built into PHP that will tell me what the parent class
05:32of each of these are if it has a parent or tell me true or false is something a
05:37subclass of something else, all right. So let's just try those real quick and
05:40see what they do. So there we go.
05:42Now, look at the answers here. So Car parent. It asks for the parent class of
05:45car and came back with nothing. That means it doesn't have a parent, okay.
05:49That's how we know.
05:51The CompactCar parent though we asked it for its parent and it was car. And
05:54then on the subclass_of, car is not a subclass of itself. CompactCar is the
06:00subclass of car, but car is not a subclass of CompactCar.
06:04So those are some methods we can use when we start programming to check and
06:08find out dynamically whether or not something is or isn't a subclass.
06:11And I just want to make sure that I at least show this you so you could draw upon them,
06:14if you ever needed those.
06:15In the next movie, let's take a look at another important aspect of object
06:18oriented programming, which is how we can modify, access to our attributes and
06:23to our methods.
Collapse this transcript
Setting access modifiers
00:00In previous movies, we have seen how we can add attributes and methods and
00:04we have seen how we can called those methods and read and write to the attributes
00:07from both inside the class using the this reference variable and also from
00:11outside the class definition.
00:13Well, one of the features of object oriented programming is that we can also
00:16restrict access to those attributes and methods that are inside the class. Now,
00:20that's not something we can do when we're not working with OOP. We normally
00:24just have access to a function if it exists or access to a variable if it exists.
00:28Now we have scope that may determine where the variable exist and whether
00:32we can get to it, but that's different. We're talking about controlling access to it
00:36specifically within the class and we're going to do that with Access modifiers.
00:40There are three access modifiers: public, private, and protected.
00:45Public is going to make an attribute or a method accessible from everywhere.
00:50It means anyone can access it anytime and this can be the default setting for
00:54new attributes and for new methods. We also have private which says that this can
00:59only be access within this class, so we're not able to call a method or an
01:04attribute from outside the class like we did when we were doing some getting
01:07and setting of those values or calling methods that were in classes. We can only call
01:11them internally inside the class. And then protected loosens up just a
01:16little bit and it says we can called them from within this class or
01:20the subclasses of this class.
01:22So if we're going to be working with subclasses a lot, we're probably going to
01:24want to make things protected so the subclasses can still work with different things.
01:28But if we know for fact it's only this class, we can go ahead and lock it
01:32down tight and make it private and that way other parts of our code can
01:36access it. And don't mistake this access control for security.
01:40We're not restricting what the public can actually get to on our application. Hopefully
01:45they can't get to any of our code or call any of our methods. They have to
01:49interact through the web pages that we generate and our code on those web pages
01:53that they never see, the PHP code, will have access to these things.
01:57So what we're talking about is our code being able to access different methods.
02:02Now why don't we just make everything public? Well, you could. You certainly could.
02:06You could make everything public all the time. This is good programming
02:10practice. It's a good habit to get into with object-oriented programming to
02:14start categorizing whether a method inside a class ought to be public or
02:18private because it will force us to keep with good programming conventions.
02:23But if you decide to make all of your attributes and all of your methods public
02:27all the time, it doesn't give you a less secured PHP application. It simply
02:32means that your objects might not be as well written as they could be.
02:36Let's take a look at how we would each of these.
02:38Okay, I'm just going to go into TextMate and open up a new document and
02:42I'll save it in my sandbox. We'll call it access_modifiers.php. Here we go and
02:50I'll go ahead and put my PHP tags on.
02:53Now I'm going to start out by just pasting in some code that will get us
02:57started. So I have just got a simple example class. I have got three variables
03:02at the top and I have got a function that just displays all three of those.
03:06Now in order to declare access to these variables, these attributes,
03:10all we have to do is instead of var is just simply change it to public and this to,
03:15let's make it protected and this one private. So that's all we have to do.
03:20We just have to declare them as being one of these types. So by default if we just use var,
03:26that's the same thing as public.
03:28So let's take our example class for a test drive and see how it works. Example =
03:34New Example and then let's echo back. Then we'll say public a and put our
03:45{example->a} and we'll go ahead and put in a br tag after it.
03:53All right, so let's just try this one now, public a, see how that works.
03:56I'm going to move it a little bit. Let's open up our Firefox and let's just go to
04:02access_modifiers, okay. So it works, no problem, and it returns one to us.
04:08Now let's try the same thing with protected b. We're going to ask it to return b to us.
04:16Okay, let's go back and try it. Fatal Error: cannot access protected property,
04:22so that is exactly what we would expect. It gives us an error and
04:25says yeah, you don't have access to that because it's protected. Only example
04:30and any subclasses of example would have access. So I'm going to come out to that line
04:35and I'm going to then take our a line again and let's try c. That's going to
04:40be private c and we can already guess what's going to happen. Let's reload it and see.
04:45Cannot access a private property, right? And that also make sense
04:49because like protected, only that class has access to that value.
04:54Now to make the point about it having access, let's try a show abc method.
05:00example and show abc. So we'll save it and we'll go back and let's reload it.
05:07You know see it comes back with 123. It was able to access 1, 2, and 3. It accesses
05:14the a because it's public to everyone, it accesses b because we're inside
05:18either the class or the subclass and c, we're also inside the class.
05:22So we're able to get all three of those values.
05:26If you like, you can pause the movie here and try to make yourself a subclass.
05:30Let's say small example and it will extend the class example and then try that out.
05:36Create a new instance of it and see when you run show abc what do you get
05:40for that. But I'll leave that as an exercise for you to do on your own.
05:43Now methods have access modifiers just like attributes but instead of replacing
05:47function what we do is we put it in front of. So public function
05:51hello_everyone. That's publicly available. protected function.
05:55I said hello_family is the name of it but that would be available to anyone in this family,
05:59meaning this class or a subclasses or private where it's only
06:04accessible to this class.
06:06Now I'll go ahead and add one more method here just like we did with that show abc.
06:10I'll just have a function called hello that runs all three in a row. So that
06:14it will be the first one, then append it to the second one, then the third one and
06:18then return the output. And you will notice that I put a little comment up there,
06:21just reminding you that functions are public by default.
06:24So we don't have to say public. It's a good practice to go ahead and say it
06:27but you don't have to. So let's drop down and try these out real quick.
06:32And I'll just go ahead and paste in a starting one here, echo, and let me just put in echo,
06:38br tag and so we'll do hello_everyone and that will just call our instance of
06:46example and ask it to do hello_ everyone. We'll see what we get back.
06:49Let's try that out quick. hello_everyone gave me back hello_everyone.
06:54So let's try the next one, which is hello_ family, and see we get there. Same thing,
07:04Fatal call to protected method.
07:07And let's go ahead and comment that out and let's try one more time.
07:12We can already guess what we're going to get I think but hello_me, hello_me and we'll try it.
07:18Call to a private method error. That's not going to work.
07:22And then last of all, let's call that example->hello method.
07:27Oh! I have to echo it this time, echo. There we are. So let's see what we get
07:32back this time. hello_everyone, hello_ family, and hello_me, all of those came
07:37out of that hello method because it has access to all three of them.
07:40So you stop and think about it for a second, what we have done is restrict access
07:44to certain functions and attributes from outside of our classes,
07:50but at the same time we're still able to get access to those, but we have to do it
07:55through another route, okay. We have to go through a side door and that concept
08:00is what I want to talk a little bit more about in the next movie.
Collapse this transcript
Using setters and getters
00:00In the last movie, we started out our discussion of access modifiers. The last
00:05example we're looking at, let me do something that I want to dive a little bit deeper in.
00:09If you remember back, even though we didn't have access to the private and the
00:12protected methods inside the class, we did have another method that was
00:16publicly accessible, hello and it did have access to those private and
00:19protected methods.
00:21It's a little bit like a bank. We can't just walk into a bank and go into
00:24the bank vault and either put money in or take money out. We have to go see the
00:28teller first. The teller can go to the bank vault for us and put cash in or out
00:33but we're restricted from going in ourselves. This type of access setup is very
00:37common in object-oriented programming, so I think it's worth looking at a
00:40little closer and we can refer it to as Setters and Getters.
00:45Those are two very strange words but what we're talking about is methods which
00:49set something and methods which get something. So setting a value and getting a
00:53value. In general, what we're talking about is working with attributes or
00:56perhaps with databases.
00:58To sit closer with Setter methods and Getter methods and to start this off from
01:02this discussion, I'm going to just paste in a simple class. I call up this
01:07SetterGetterExample class and you will see that it has an attribute a and a by
01:13default is 1 and it's private. So we cannot access it from outside the class.
01:17We have already seen how we try to create a new instance of it and then access
01:21a like this that it will fail for us. That won't work; it is restrictive.
01:25However, we can have a Getter method which I have called get_a and it's public
01:32and we have access to it and it has access in term to the private value of a.
01:38So it's a lot like our bank teller, we can walk into the bank but we can't go
01:42in the vault directly, it's private. But we can go to the publicly available
01:47teller, who can then in turn go into the private vault area.
01:51And then the second method is the Setter, set_a and it takes a value as an
01:56argument and all it does is set the value of a equal to that value. So let's
02:01try our Getters and Setters out.
02:02I am just going to simply echo back the value of get_a so that it should be 1
02:08and then I'm going to set it to the value 15 and get it again, just to make
02:11sure that it's working. Let's save that and we'll go back to Firefox and we'll
02:15just load up access_modifiers2. So there we're 1 and 15 that it will return. So
02:21those are Getter and Setter methods and that's how they work.
02:24Now you may be wondering why go to all these trouble, why write all these extra
02:28code, when we can just simply declare a as being public and then we could work
02:31with like a normal variable and we can set values and get values directly to
02:36the variable. But the reason why is like our bank teller example because the
02:40bank teller serves a very useful purpose. They check and make sure we're who we ay we are,
02:44sand they check and make sure that our account has the right amount
02:47of money in it before we make the withdrawal. They may also initiate some other
02:50actions before they finish with our transaction.
02:53So, for example, the bank teller might make a note about how many withdrawals
02:57have occurred for the day. In the case of our about application, it's the exact
03:00same thing. We can perform other actions before we return that value.
03:04So let's say that we had an action that was something like log_users_ip_address
03:11and we have to write that function, but this could take place before we let any
03:15one get that value out of there. Or we could check and make sure that they were
03:18logged in as an admin user perhaps, before we get that value. Maybe only admins
03:22are able to get that value back.
03:24Now there are some PHP developers who prefer to make most of the attributes,
03:28private and protected, and then control access to them through methods like
03:32this. I'm not one of them. I use Setters and Getters but I do it when
03:36necessary, when I need to intervene in the process either to take care of some
03:40other business before we return the value or set the value or when I need to do
03:44some kind of an access control or something like that before getting to the value.
03:48Otherwise, I go ahead and just make it a public attribute and that's how we'll
03:51be doing it throughout this tutorial. But I'll leave it up to you to decide
03:53which one you are most comfortable with.
03:54Now that we have seen the three Access modifiers, I want to take a look at the
03:58different kind of the modifier in the next movie.
Collapse this transcript
Working with the static modifier
00:00In addition to the three access modifiers that we have just learned, there is
00:03another modifier that we should talk about and it is with the keyword static
00:08and it's a static modifier. We can modify an attribute or function with it and
00:11we can used it even in conjunction with all three access modifiers, so really
00:16it's different because we can used both together.
00:18Let me give you an example of its usage in the class and then we can talk about
00:21how it works. So, an example of using in the class would be like this. You have
00:25a class student and it has a variable total_students and I have declared it's
00:31being static, then I have got function welcome_students which is also declared
00:36as being static. So what is static?
00:38Well, if you remember back to Chapter 2, when we were talking about function
00:42that had static variables and then we use them like a counter inside there
00:46because we said that they would stick around. Well, this kind of works the same way.
00:49Now, standard attributes in the class stick around as long as the instance is around.
00:54But with static, the big difference, if to the attribute or the method,
00:58is around even if there is not an instance. Let me just repeat that one more
01:03time to make it clear, we have access to both total_students and the method
01:08welcome_students even if we don't have an instance. It breaks the rule that
01:13we're talking about earlier when we're talking about creating instances in
01:16order to have these things, static allows us to do that because the static
01:19variable is tight to the class itself not to an instance.
01:24In other object-oriented languages, this is often referred to as class method
01:28or a class attribute. Now in PHP, we just simply call it Static. We say it's a
01:33static method or static attribute. Because we don't need to create an instance,
01:37the way that we refer to them is a little different because we need to specify
01:40which class we're talking about, so we need to first say what class, when we do
01:45with an instance we have created, that class, we have an instance of that
01:48class. So everything is directed to the direct place.
01:50But we need to be specific. What if we had two classes they both had an
01:53attribute called name? How do we know which one we're talking about?
01:56So we'll need to specify student and then instead of the arrow notation which
02:03is used for instances, we're going to used two dots. And we'll talk a little
02:07bit more about these dots in the next movie. For now, just note when we're not
02:11dealing with an instance, we use the two dots and then the $ sign
02:16total_students.
02:19And just so that you can really compare the difference, what we normally would
02:22have is something like student = new student and then we would be able to say
02:29echo student and then whatever value. Let's say it was total_students, let's
02:36say that that was a non-static method. Now that's what it would normally look like.
02:41So if you notice here, this call knows where to go find its code because it
02:46knows what class it belongs to. So it knows where total_students is located.
02:52But if we don't have an instance, then we also need a way to tell PHP where it
02:58can find this variable, right, we might have a lot of classes and if the name
03:02of the variable something like first name, how does it know where to go find it,
03:05how does it know which class to look at. So we're going to need to
03:07reference the class.
03:09And then because we don't have an instance we use two dots instead of the
03:14arrow, okay. We'll talk a little bit more about those two dots. But for now
03:18instances are going to use that arrow notation right, -> and then instead,
03:26we're going to say total_ students after the two dots.
03:30So take a second and notice the differences there, notice the $ sign is here,
03:34there was not a $ sign here. This is an instance, this is a static call, okay,
03:40so let's go ahead and just try that out so that you can see it working.
03:44Go into Firefox and we'll open up static _modifier, there we are, it comes back
03:51with 0 which is the value of students, and then let's go ahead and just put br
03:57tag at the end and then we could do the same thing with echo
04:02Student::welcome_students and we'll do our br tag again.
04:11And that's how we call a method, still with the double parenthesis after but
04:15also still using these two colons in between the two. If we do that you will
04:19see that that comes back just as well.
04:22And we can work with this just like we would with normal values, you see here
04:25that I have done welcome_students and I have passed in greetings as a variable
04:29to it. You will see here that I have got a student, I set it equal to 1 and
04:34then student total_students, so they work just like normal attributes and methods.
04:40Now the other thing that's really different about working with static methods
04:44is that because it's not an instance, we can't use this. So normally we would
04:49do something like this. It's a public function add_student and then we would
04:53increment it this way. But we can't do that, we don't have access to this. In
04:57fact, I'm going to put a note up here at the top that says with static methods
05:03you can't use this. Okay and this can be a good reminder for us.
05:11So instead we need another way to refer to this so I'm going to make this
05:15method static also. So since we can't use this, we can still use this double
05:21dot notation. There we go student:: total_students and then we need a $ sign
05:25too. So that will actually reference the correct value for total_students.
05:31Now you may be wondering, do we need static in front of this one? Can it just
05:35be a public method? It's best for you keep your static attributes in your
05:38static methods completely separate from your instance methods, the normal ones
05:44that are working, the non-static ones. That's how they are meant to be used, as separately.
05:48In fact, if in your PHP error settings in php.ini, if you had it set to strict,
05:54it will complain if you call a non- static method in a static context. In other
05:59words, you start mixing between them and you have a static method, they call
06:02something that's non-static and so on. You'll start getting errors.
06:05So in general, all the static methods go together, they only call other things
06:10that are static, all of the non- static ones belong to instances and you can
06:14make reference to them. That doesn't mean that you can't ever use them;
06:17you just have to be careful about how you do it.
06:20The last point that I want to make is that static variables are shared
06:24throughout the inheritance tree. Take a look at the code that I just pasted in
06:27there. I just have got a simple classes called One, Two, and Three. There is a
06:31static variable called foo that gets inherited into all three of them and I
06:35just set a couple of values for foo, One, Two and Three.
06:37So if you echo those back what will the results be and the answer is three for
06:43all of them. Now that may be a little bit counter intuitive, you may think that
06:47each class should have its own but that's not true, it's define once and
06:52whenever we talk to class Two, it actually is referencing that same static
06:58value that's in class One. So just be careful about that because that trips a
07:02lot of PHP developers up.
07:04So I'm just going to save it and just try one last time, just to make sure
07:07we do get those 3s at the bottom and that shows that these static variables are
07:11shared between parents and their children.
07:13So you might be so wondering when would you use static variable and methods and
07:18it's when you don't actually have an instance. Let's say that we're talking not
07:22about a particular student but about the total number of students that have
07:27been created. That would be something that we can keep track in a static
07:30variable. We might also have some very basic class information.
07:34Let's say that we wanted to keep these student types in there and we might have
07:38freshman, sophomore junior, senior as being the different types of students
07:42that could be chosen. That could be in the static method that we would have
07:46access to all the time. The student class could report back to us about what
07:50kinds of students there could be even if we don't have a students.
07:53Now I have said earlier that we would talk a little bit more about these double colon.
07:57Let's do that in the next movie.
Collapse this transcript
Reviewing the scope resolution operator
00:00In this movie, I'm going to take a little closer look at something called the
00:03Scope Resolution operator. We saw it in the last movie when we were working
00:07with static variables and static methods and it's those two double colons.
00:11That's what it is, the Scope Resolution operator.
00:14Now in PHP it also has a much bigger fancier name, which I'm sure I'll
00:17mispronounce Paamayim Nekudotayim. If we break that down, it's Hebrew and
00:25it means One Doubled Dot Doubled. So one doubled dot and then doubled again and
00:30that's why we have two colons. So that's the double colon in Hebrew.
00:33Now why should you care what it's called in Hebrew? Because that's what PHP
00:37calls it internally. If you remember, PHP was developed by Israelis. Sometimes
00:42you will get an odd error, it will say Parse error, syntax unexpected T and
00:47then you will get this long word and you are like what in the world is that thing?
00:51I have no idea what went wrong in my code. Well, in English, that error
00:56means that you screwed up the reference to an object or to its scoped
01:00attributes or methods. Let me show it to you so you will recognize it.
01:03Here I am in the same static modifier page that we were just working in. You can
01:08put this anywhere but I'm just going to make a bogus request here. I'm just
01:11going to say $make::an_error, there we go, and that's not going to work, right?
01:19For all sorts of reasons, that's wrong. Let's try and load that up.
01:23There we are. Now we see the error, unexpected double colon. So that's what
01:28it's telling us and so what it lets us know is we screwed up the reference.
01:32So you can think of the Scope Resolution operator as steering PHP to the right
01:36place to find a variable. Where is the scope for this thing? It's inside a
01:40certain class. If you think about it, a static class variable works pretty much
01:44like a normal variable as long as we prefix it with a scope. We saw that in the last movie.
01:49It's just a variable that's being maintained in a class. The class is its
01:53scope. Keeping the class on a specific scope helps to keep it conflicting with
01:57other variables. So, for example, we can have this Student::$total_students but
02:03we could also still have something like $total_students = 20 and that's a
02:09separate counter. That's a separate variable that we're working with, because
02:12it has a different scope.
02:14So because they stick around all the time thinking of these variables as being
02:19normal variables but just with a certain scope might also help you to remember
02:23that you still have to put the dollar sign in front of them, which we didn't
02:25have to do in the instance variables.
02:27So that's just a little more insight into what these double colons are and also
02:31a heads-up for when you get this crazy error message, what does it mean?
02:35It means that you have used double colon someplace and you made a bad reference.
02:40It could not find the code that you were looking for, the scope was wrong.
02:43Now that we know a bit more about the Scope Resolution operator, let's look at
02:46how we can use it to reference an instance's parent as well.
Collapse this transcript
Referencing the Parent class
00:00In the last movie, we talked a little bit more about the Scope Resolution
00:03operator, those two double colons. In the movie before that, we talked about
00:07how to use the Scope Resolution operator to reference the static attributes and
00:11methods inside of our class. In this movie, I want us to look at how we can use
00:15that same Scope Resolution operator when dealing with inherited classes, how
00:19subclasses can refer to methods that are in their parent class.
00:23So I'm going to open up TextMate and I'll just open a new window and save it as
00:29parents.php in my sandbox and we'll start out with our PHP tags. Now I have
00:35already got a real simple class here. This is what we were looking at a couple
00:38of movies ago where I have got a static attribute and a static method in there
00:42and $a = 1 by default and then modified_a just simply adds 10 to it.
00:46Now we talked about the Scope Resolution operator and we also talked about self
00:50and how self is a keyword that just simply means $a. So we can use either one.
00:56It's convenience method that allows us to just simply refer to whatever this
00:59class is. That's the attribute that we want to look for.
01:02So since we understand that, let's now talk about inheritance and we know that
01:05if we have a simple class like B that extends A that it inherits those methods
01:11that are in A. So that includes those two static methods. So already we know
01:16that we could do something like this and it would work for us. Let's save it
01:19and let's just try it out to prove to ourselves that we can still access a and
01:22modified_a by simply looking into the class B.
01:25We will go into Firefox and instead of static_modifier let's load up
01:30parents.php. So there it is. It pulled back those two values, 1 and 11. Now
01:35what I want us to understand here is how we can reference the attributes and
01:40methods that are inside A from inside B. So here I've put in two simple tests,
01:45they are also static methods. The first one I have just called attr_test for
01:49attribute test and the second is a method_test. And each one is going to refer to A.
01:54Now this shouldn't be any surprise, just A::$a. Now we also could refer to B
02:01and get the same value back, right? Because it is also inherited, those would
02:04both work. Well, we also have the ability to call parent. That's the other
02:09keyword that I want us to see and we can ask it to return the value that it
02:13finds in its parent, in A.
02:15So let's go ahead and try this out and then we'll talk about why this is
02:18important. So I'm just going to put in two more tests here, these are going to
02:21call my new test methods that I have written up. So I'll just save it, we'll go
02:25back and we'll reload and you will see that it still works.
02:28So just like self, parent becomes a convenience method that we can use to refer
02:33to whatever the parent's attributes are. Now up until now, I have been really
02:37trying to stress the difference between static or class methods and attributes
02:42and instance methods and attributes when we actually have an instance of something.
02:46Well, the odd thing about parent is that it breaks down that division. It
02:51totally violates all the rules I have been telling you. Up until now you could
02:54safely say well, use the double colon whenever you are talking about something
02:58that's static and we could just associate the two, ::static. Then we would use
03:03the $this whenever we were talking about an instance. So we would have those
03:07two different ways to work depending on which one we're working with.
03:10But with parent, we can use it with instances too. In fact, it's important to
03:15be able to use it. What's even weirder is that it only works with parent
03:18methods, not with parent attributes. If you think about it, it makes sense,
03:23because let's say, for example, we have $object = new B. So we create an
03:27instance of B and it instantiates all of its aspects, but A still hasn't been
03:33instantiated. So we can't really refer to attributes that are there. We can
03:38look up what the methods would be but we don't have attributes because it's not
03:42instantiated.
03:43So I realize that this may seem a little confusing because it is breaking those
03:46rules. So let's see how it works and I think it will become clear. I'm going to
03:49add a new method here, something real simple, a public function called hello,
03:53and it's just simply going to echo back hello to us, super simple.
03:56Now we know that in our class B, we could have another public function
04:01instance_test that's going to expect us to have an instance and it's going to
04:04look for this hello and hello will be inherited by b. Let's go ahead and try
04:09that out. So I'll come down here and let's just say instance_test. Let's go
04:13back and reload it and sure enough there it is. We get Hello returned back to us.
04:18So what I'm telling you now is that we actually can do this. parent::hello
04:24and we'll save it, we'll go back and we'll reload it. You will see that it
04:27still works, both of us work for us, not just this, but also parent.
04:33Now why would we ever want to do this? Why do we ever still want to have access
04:39to both this hello and the parent's version of hello? Well, it actually can be
04:44really useful to be able to refer things back to the parent to find out how
04:50the parent would handle it in addition to be able to find out how this class would handle it.
04:54Let me give you a super simple example, I'm just going to override hello in the
05:00B class. So instead of hello being inherited, it's been overridden now. So take
05:05a second to look at it, pause the movie if you need to, but I want you to think
05:08about what it will do if we now call object hello. So we're calling it on B as
05:13an instance method of B. The first thing it is going to do is it is going to
05:17call this echo statement. Then it's going to call the parent method hello and
05:24do whatever is there and then it will do another echo statement.
05:29That's the idea here, we're in the class we've overridden, but we still have
05:33access to the old overridden class. That's extremely useful. We could have it
05:39return a value to us. We could say, for example, see if the parent class is
05:42able to find a record in the database. If it is not, then I'll try and handle
05:47it or vice versa. We could say well, let class B look for something in the
05:51database and if it's unsuccessful, then ask class A if it can find something in
05:56the database. We can still access those old behaviors by using this parent notation.
06:01So let's try it out just to prove that it worked. So there it is. You will see
06:05that it did the asterisk, then went to the parent method, returned hello and
06:09then did the asterisk right after it. So to sum all of this up and make it
06:13really simple for you, when you are working with static methods, go ahead and
06:16use this parents method with these double colons. That's when you should use it,
06:20just like we were following in the rules. But the only time that you should
06:24use it with instance methods is when you are trying to actually access the parent method.
06:31In this case if we don't actually mean that we want the parent, then we could
06:35just do this hello instead. So use this when you are working with instances
06:41expect for this one case. In the next movie, let's look at constructors and
06:46destructors when working with classes.
Collapse this transcript
Using constructors and destructors
00:00In this movie, we're going to look at constructors and destructors.
00:03Constructors and destructors are special methods that automatically get called
00:07whenever an object is created or destroyed. So the idea is that whenever an
00:11object is created, stop while constructing it and perform the construct method
00:17and whenever we're destroying an object, stop and do the destruct method as well.
00:22Let's go into depth on constructors first, because they are far more useful.
00:26Constructors are going to be ideal for any initialization or housekeeping that
00:30an object may need before it's actually going to be used. Now in PHP 4.0,
00:35constructors were methods that had the same name as the class. Now, of course,
00:38we're not using PHP 4.0 here, but I want you to see it, just so that you are
00:41familiar with it and if you are looking at some old code you will recognize
00:45that and know that that's what it is. It has the exact same name, the class is
00:48table, so the function is called table. That's a constructor.
00:51Now to give it a better name in PHP 5.0, it is __construct and that's how we're
00:57going to name the constructor and that is going to be the automatic method that
01:01will get performed whenever an instance of class Table is created.
01:06Let's see how it works.
01:07I am just going to open up TextMate and start a new window and we'll do Save As
01:13constructors. Even through we're going to talk about destructors, I'm going to
01:17go ahead and just call it constructors for now, php tags. So let's start with
01:22that class that we were just looking at, Table class.
01:24So here we can see more clear. That's __ construct and this is our chance to do
01:29some housekeeping. So let's say just as a really simple example that we had a
01:33public attribute called $legs on the table. I'll then make it say down here
01:38$this->legs = 4. So whenever we instantiate a new table, it will have 4 legs.
01:46Let's try that out. Let's just say $table = new Table and then echo
01:53$table->legs and let's go ahead and just put our <br> tag at the end.
02:01Let's bring that up in Firefox and try it out. Constructors, there we are. So
02:07this has the exact same effect, of course, as if we had put legs = 4, but
02:11imagine that we wanted to do something much more complex than that. Imagine
02:15that we maybe wanted to stop and check a database or that we wanted to do a
02:20little bit of research into the state of other classes and their static
02:25variables and things like that.
02:26If fact, I'll give you another real simple example that we can look that. Let'
02:30say that we had static public and then let's keep track of total tables as a
02:36static value. We'll set it to zero to start with. So now whenever we create a
02:41new table, let's increment that value, Table::$total_tables++.
02:49So that's going to increment it every time we create a new instance, the class
02:53is going to keep track of how many total tables have been instantiated.
02:58Let's give that a whirl. Let's just come down here and I'll paste a couple of usages
03:03of this so we can just see it.
03:04I am just going to simply echo back the value, it should be zero here, and then
03:08I'm going to create a new table and then echo that value back and then I'll
03:11create another new table and I'll echo the value one more time. So let's just
03:14try that. Oops! It came back actually it was 1 here because we had already
03:20created the table back up there. So this will actually be 1 the first time.
03:24Again, this is a really simple example but you can now see how we can begin to
03:29actually take care of some business each time one of these objects is created.
03:32I'm not going to go into the full example, but if we had this as a subclass,
03:37let's say extends Furniture and then down in our construct method we could
03:42refer to the parent method construct.
03:48So now once we have done all of the construction that's involved with the Table
03:53class, it will jump up to the Furniture class to see if there is any
03:56constructing that needs to take place there. We saw that parent Scope
04:00Resolution operator allows us to do that. But again I'm not going to go ahead
04:04and fully implement that, I just wanted to point out that it was possible.
04:07The last point I want to make about constructors is it they also can take
04:10arguments. So, for example, $leg_ count and I can say = 4 and then I'll just
04:16take $leg_count here and set it equal there. Now, notice that I have a default
04:22value for 4. If I did not have that, then every time I create a table I would
04:26need to pass in an argument here 4, 5, 6 so on.
04:31It's going to be expecting me to pass an argument just like I would to a
04:34function. I'm going to pass it in to those parenthesis that are after the class
04:38name. That's why those parenthesis are there, in case you are wondering, it's
04:42what we're passing into the construct method.
04:44It's always a really good idea to give a default value there just so that if
04:48you ever do create a table without one, that it doesn't give you an error and
04:52it's doesn't say hey, wait a minute, I was expecting an argument and I got
04:55nothing. So even if the argument is null or zero or something like that, go
04:59ahead and give it some default to fall back to for constructors.
05:03Now, constructors are going to be really useful powerful tools, destructors not
05:07as much. Here is what it looks like, it's __destruct and then two parenthesis
05:12just the same and then we could have it do something. I would have it say
05:15$total_tables--.
05:17Now the reason why it's not that useful is because most of the time we just let
05:22our objects stick around that we have instantiated through the entire request.
05:27So if the user hits a page, it goes and creates all the objects it needs. It
05:30generates the page for the user and then PHP destroys everything. It doesn't
05:35hang on to those objects. It doesn't keep them around. They all get destroyed
05:39and the destruct method does get called then, but it kind of doesn't matter at
05:42that point because it's unloading everything including the value of
05:46$total_tables, so why bother going through an decrementing each of those?
05:50The one time it is useful is that you can call it directly if you are going to
05:54destroy an instance. So that's why it's there, it's not used that much. I would
05:58say it's used 1% as often as you are going to use constructors, but at least
06:02you know what it is. So spend a little bit of time playing with constructors
06:06until you get comfortable with them. In the next movie, we'll look at cloning objects.
Collapse this transcript
Cloning objects
00:00Now that we have seen how to create objects and specifically how we can use a
00:04constructor method on those objects, I think it's time for us to now talk about
00:07how to copy objects. We call that cloning. I'm going to TextMate, I'll open up
00:12a new window and let's just save this as cloning.php and we'll go ahead and
00:19start our PHP tags.
00:21Now in our earlier discussion about references, I noted that all objects use
00:25reference assignment, by default. So, for example, if we have a class called
00:28Beverage which just has one attribute, name, then we can create a new Beverage,
00:34assign a value to name. Then if we say $b = $a and we change the value of b's
00:39attribute name, it will also change the value of a's name because it's a
00:44reference. Let's just try that to just make sure we remember that.
00:47I am going to open up Firefox and we're going to look up cloning, tea.
00:52So you see coffee got disappeared. Tea became the new value for a because
00:56their reference is pointing at the same object. But what about when you don't want it to be
01:00a reference? What about when you want to actually make a copy of it?
01:03How do you actually copy that object over?
01:07And the way that we do that is by using clone. So clone $a will then make a
01:13copy of it. So now when I say $c-> name = "orange juice", then echo back the name,
01:22we can see what that's going to return for us. I'm going to need a <br> tag in here.
01:26All right, let's try it now.
01:30Back over here, you will see that a is still equal to tea, the value of that
01:34didn't change. If we want to just check it, we can also just ask what the value
01:37of c is and I'll just move this <br> tag down here again. So there we go, now
01:43you can tell that changing the name of c did change it because it was a copy.
01:49But it did not have any effect on a because it is no longer a reference. For b,
01:53that wasn't true. They were references to the same thing.
01:56I think that should be self-explanatory enough. The other important thing about
01:59cloning and using that clone is if you remember we had the construct keyword.
02:02So here is a real simple construct method that will get called automatically.
02:07Whatever housekeeping is done in that construct method is not done when we clone it.
02:12It's only when we create a new and not when we copy it, instead, we have a
02:16clone method, __clone. So whenever this object is cloned, then do this next
02:23step. Let's just try this with the same beverage and just see what happens.
02:26Let's make sure I have got some <br> tags, I do. So the first time that
02:29we create the object and we assign it to a, we get "This new beverage was created."
02:33Then when we make a reference with b, nothing happens, because it's just a
02:37reference. It's not until we get down here and we actually make a clone that
02:41clone method gets called. So that automatic clone method is going to work just
02:45like a constructor and it's going to be your opportunity to do the same kind of
02:48housekeeping whenever you clone an object.
02:50So now that we know how to make both references to objects and how to clone
02:55objects, in the next movie, let's talk about how we can compare objects to be
02:58able to tell whether or not it's a reference or a copy.
Collapse this transcript
Comparing objects
00:00The cloning that we discussed in the last movie presents us with
00:03a great opportunity to talk about comparing objects. This is how we can tell if we have
00:07two objects with the same reference or two objects that merely look alike.
00:11There are two operators we can use to compare objects. There is the normal
00:15Comparison operator, which is just equals equals, or there is the stricter
00:19Identity operator, the equals equals equals. Now don't worry if you don't
00:23remember the name Identity operator. What is important is that it is a stricter
00:27form of comparison. So in the first case it's going to compare whether
00:30the two objects have the same attributes, whether or not they are basically the same.
00:35But the stricter Identity operator is going to require that the two objects
00:38compared actually point with the same reference object.
00:41I am going to go to TextMate, I'll open up a new window and let's just save
00:46this as comparison.php and we'll go ahead and start with our PHP tags.
00:55Now let's imaging that we have a real simple object. I'm just going to call it Box
00:59and I'll just give it a simple attribute called name. So let's make a reference
01:03to the box first of all. So, that's just a real simple reference assignment and
01:07we know that always takes place with objects. Then now that we know how to do a clone,
01:12let's also do a clone version of it, just so that we can see that.
01:16Then just so that we can compare that to something else, let's now make another one
01:20called box changed, okay. So just be clear, this is something different.
01:23We're cloning it again, but this time we're just going to change one of its attributes.
01:27Then last of all, let's just make another box, which is a
01:30completely separate instantiation of new box.
01:35So now that we have these different instances to work with, now let's just try
01:38writing ourselves some simple tests. I'm going to paste in the tests I have
01:42already written just to save me time from typing. You can pause the movie be if
01:45you want to copy them down to work along with me. hat I'm simply going to do on each one
01:49is echo back true or false depending on the resolves of the equals operator, ==.
01:56So I'm going to compare box with box weapons, box with clone, box with change,
01:59and box with the another box and that will then give me a comparison to say
02:04in which cases is this true, when are they the same,
02:06and we'll be able to see the difference. Let's bring that up and try it.
02:09I will go to Firefox and let's bring up comparison.php. So I got true, true,
02:16false, and true. So let's just come back here and make ourselves some notes.
02:20This is true, this one was also true, this one was false, and this one was true.
02:28So, let's look at what happened there. The reference is still equal.
02:32They point to the same thing, their values are the same. The clone, also equal.
02:37Even when though they don't point to the same object, the attributes are the same.
02:40They start out with the name just being box. So there is no difference.
02:44It says, yeah they are the same.
02:46Box_changed is the one that's false, and the reason why is because the
02:49attribute name got changed. It's now changed box. So, it returns false and
02:54even when we compare box with another box, a completely new instance,
02:57which is basically the same thing as when we did the clone version, it comes back true,
03:01because the attributes are essentially the same. It's pretty much the same thing.
03:06Now let's try those tests again, but this time we're going to do with
03:09the stricter Identity operator. So, equals equals equals. You can actually just
03:13copy and paste that top text again and then just go in and change each of those
03:17to be ===. And let's try that and see what that does.
03:20We will come back, reload. I put an extra br tag in here so I could separate them.
03:24Notice only the first one is true; the rest are false. So, I'm just going
03:28to add my notes here. That's true and the rest of them are false.
03:37The only one that passed the test was the reference. They point to the exact same thing.
03:43When we cloned it? No, not the same, different thing. When we changed it? Of course
03:48it's not the same. It didn't even pass the other test. And when we created a new object,
03:52a new instantiation, it said, no, those are two different things.
03:55They point to different places. So I hope those Comparison operators are clear.
03:59Just to summarise, when we're comparing objects, two references will always
04:03pass both tests, equal equal and the triple equal, the Identity operator.
04:06Instances with matching attributes will pass the == test. So, yeah.
04:11The attributes are the same; they seem pretty much alike. It doesn't matter if
04:14they point to the same data or not. But they will fail the identity test,
04:18because they don't refer to the same object. And then are of course instances
04:21with different attributes will aways fail both. It will say, "Oh! That's
04:24completely different. That's John Smith and not Jane Doe. I can tell they are
04:29not the same right away." And they failed both tests.
04:31So now do we understand how to compare objects, we understand references,
04:36we understand cloning, we understand constructors, we really have a good
04:40understanding of how object oriented programming works in PHP and we're ready to
04:43actually put it into practice and to start our project they will help us to
04:47bring all of this knowledge together. And that's what we'll start with in the next chapter.
Collapse this transcript
5. Photo Gallery Project Setup
Overview of the project
00:00Now that you have the basics of working with objects in PHP, the next step is
00:03for us to take that and apply it to a real world project. For that project I
00:07have selected a photo gallery for us to design. What I'm thinking of this
00:11website is like Flickr, for example, where you are able to display a lot of
00:14different photos online. People can view them, they can comment on them,
00:18that kind of thing. Of course we're not going to be as full featured as those kinds
00:21of sites, but this would be something that you could potentially showcase your
00:24own photographs to friends and family and continue to improve it until it did
00:28have a lot more features.
00:29So, the way I'm thing about this project is that there will be two parts.
00:33There will be a public side and a private side. The public side will be available to
00:36our site visitors. The admin side will require password for people to get in.
00:40The public side will have an overview of all the images in the gallery and if
00:44we have more than, let's say, 10 to 20 images on a page, we want to have
00:48pagination, which would mean that we would have a link that says Next, and that
00:52would let us get the next 10 or 20 images.
00:54So that's called pagination and we'll be seeing how to do that. Then of course
00:57if you click any of the images, you would get a full size image view,
01:00and we're going to let our site visitors comment on our photos as well. So there will be
01:04a simple web form where they can post comments about the photographs.
01:08In the admin area, of course, we're going to need to have a login area and that
01:11functionally. We saw how to do that in the essential training. We'll look at
01:14that again from an object oriented perspective, and create admin users, so that
01:18we have users who can login to upload images. That's how we'll get our
01:23photographs in there, and of course delete images and then we'll also want to
01:27be able to review and delete comments as well.
01:29So that's an overview of sort of the main functionality that I have in my mind.
01:31We might add a few other features as we're going through, but that will be the
01:34core of our photo gallery.
01:35Now, let's think about it from object oriented perspective. What objects are
01:40we going to be needing inside of this project? A good rule of thumb is any
01:44database table that you have is going to have an object associated with it. So,
01:48we know we're going to have to have users, we're going to have to have
01:51photographs, and we're going to have to have comments. So we're going to need
01:54three objects, one for each of those, and creating a new user would then let us
01:58ask it for its first name and last name, for example. Or, for a comment, we can
02:02ask for its post time. That's all object oriented.
02:05Now what might not be as obvious to you are some of the other objects that
02:08we're going to be using. One is going to database, and we're going to have a
02:12single object that's going to manage our connection to the database. Then we'll
02:15talk about why that's a good idea. If you just think about it in abstract terms
02:19it sort of make sense that there is an object out there that's the database.
02:22We want to go to the database and get something. So, think of it that way. It's an
02:25object. It's abstract, because it's on our computer's hard drive, it's a piece
02:29of software, but it is an object that we're putting things in and out of.
02:32The same thing is true for session. We talked about how to use sessions in the
02:35essential training where we maintained the stat of whether we were logged in
02:38and out, we'll be doing that with an object this time. And last of all,
02:41we're going to have an object that's going to manage pagination for us. Now that
02:45might not be as obvious as some of these other ones, but it will be helpful to
02:48have an object that can contain all of the knowledge about whether or not
02:52we have more pages, how many pages there are. We'll put that all into a single object,
02:57and by the end you'll see why that's beneficial.
02:59Now we may create some more objects along the way, but these are the core ones
03:02that we're really going to focus on, and to start with I want us to focus on a
03:05making our database connection. So we're going to start there.
Collapse this transcript
Creating project and asset directories
00:00Before you start coding on the photo gallery project, I wanted to do some
00:03housekeeping and set up the project directories for the project. Now that may
00:07seem like an incredibly mundane task, but there are some important points that
00:10I want to make while we do it. So we're going to do it together.
00:13So we'll create our new project directory inside the same place we created the
00:16btb_sandbox. For me that's inside my hard drive, inside users, inside my
00:21username folder, inside sites, and that's where I have got my other folder.
00:25You will want to go to the same place where you put your btb_sandbox folder. So
00:29I'll create a New Folder, and we'll it photo_gallery.
00:35While I'm here, I'm also going to ahead and choose from the File menu to make
00:39an alias. If you are in Windows that would be a short cut and let's go ahead
00:43and just drag that onto the desktop and I'll just change the name of it real
00:48quick, and we'll be right over here. Now it will let me get back to this folder
00:55anytime very quickly.
00:56So inside the photo gallery folder, now we need to set up a few other folders
01:00as well. If you think about the essential training, we did the same thing.
01:04We created a folder, for images, and a folder for style sheets and a folder for
01:11JavaScripts and we had a folder for our includes where we put all our
01:15functions and everything like that.
01:17This time we're going to be creating two ones as well. We'll have a folder
01:20called logs and that's where we put our log files. Then last and most
01:25importantly we're going to have a folder called public, and this a big
01:28difference from what we did in the essential training, because the images, the
01:31JavaScripts and the style sheets all contain information that should be
01:37available to the public.
01:38If someone browses to our website, their browser has to have access to those
01:42things. So they are public. So I'm going to move those into the public folder
01:46and that's where we're putting all of the code which is public, everything that
01:51their browser needs access to.
01:53So all of our pages will be there. Even that they are password protected, so
01:56that they are part of admin area and not part of the public area. This is
01:59different. This is public, meaning that a browser you have given the right
02:03password and credentials could get the pages from here.
02:06The includes and logs though are going to be outside the public folder, because
02:10the public is not going to have access to either of those.
02:13Now our scripts will still have access to them. They can go back in the
02:16directory and see what's in the other folders and in fact in our includes
02:20folder that's where we put all of our objects, but all of our pages will reside
02:24inside public.
02:26I mentioned that, sort of offhandedly in the essential training. That's a
02:29really important security feature. Now that you know enough, you are in the
02:32graduate to doing at this way. So that, things that public should not hv access
02:35to sit back out of outside of that folder and so we can reference them by using
02:40absolute powers and the power system.
02:42So now that we have that up end running, let's just go to TextMate and I'll
02:45create a new file and let's just run a simple a PHP test here. Let's just say
02:50echo Is this working and close php tags, and we'll save it as index.php. And
03:01let's just navigate to the photo_gallery. And then inside public, that's where
03:06this is going to go. Save it. I'll close it up.
03:10Let's open a Firefox to make sure that we got PHP working and we can get to
03:14that directory okay. So it's going to be a local host and then if you are on
03:18Mac, it's going to have that tilde and your name, and so it will be
03:23photo_gallery, but that's not enough, we also have to say public. Now when set
03:29this up on a public server for the world actually have access to. What we want
03:34to do is wae want to tell u serve up the contents of the public folder. That
03:38will be a starting point. Or if we were on a shared host or something. Or if
03:42you are on a shared host or something, we can say you know the public_html
03:44folder points to this or we make an alias or a shortcut or a same link or
03:48something like that, but you are not going to want to have your whole path
03:52exposed to get to that public folder if you can help it, because everyone's
03:56hosting situation and servers are different.
03:58I am not going to go into detail about how exactly you would set that up, but
04:01the point is that you want to point it to the public directory, but on our
04:05development machine, this is still fine and we know that php is working.
04:09Before we move on, we can also create a couple of other core pages.
04:12If you remember in the essential training we had another file that was called
04:16functions. Now just go ahead and save basic php file inside the includes folder
04:24and I'll call it functions.php. So let's go ahead and drop a couple of
04:29functions in here. We can put our strip_zeros from date functions that
04:33we worked on in chapter two. That might come in handy for us.
04:36Another one that I really like, that I think is really handy, is that redirect
04:40to functions that we did in the essential training. We'll make use of that
04:43again here, and then one last one. We didn't do it as a function, but we did do
04:48the code for it, which was outputting a message. When we were learning
04:51messaging, we saw that we would simply output a message with key tags around it
04:56or nothing if there was no message. So we'll make use of that as well. Let us
05:00get started.
05:01So those are core functions there and the last thing that I want us to create
05:04is I want us to just go ahead and start with a basic style sheet, and you can
05:08pause the movie if you need to copy this down. It's a very similar to what
05:11we did in the previous training, I have just got the site colors up at the top and
05:14then I have got some basic CSS here. So this will just give it some basic
05:17structure, and I'll just save that in the public folder inside style sheets and
05:23I'm going to call it main.css.
05:25Now remember you can pause the movie, if you need to, to take a look at these.
05:29It's just some really simple styles, very similar to what we did in the
05:32essential training. Couple of differences, I'm using minimum height which, IE 5
05:37and 6, don't really like, but everything after that we'll use it, and that will
05:40allow our site to be a little longer than 600 pixels. I have also added a style
05:45here that will allow me to have bordered tables. So I can give a table class
05:48bordered and that will give all the borders to the table that it needs.
05:52So again you can pause the move, if you want to copy that down or you can use
05:55your own styles. This will also be included in the exercise files for premium
05:58subscribers. So I'll save that that and close that up. So now we have the basic
06:02file structures of our website. And the next step is for us to take a look at
06:06setting up the MySQL database.
Collapse this transcript
Creating a MySQL database
00:00There are a couple of ways that we can set up the MySQL database.
00:03In the previous title, we saw how we could use phpMyAdmin. If you are comfortable with
00:08that and that's all set up, feel free to go ahead and create a new database here.
00:11You can also issue raw SQL commands through phpMyAdmin, but I'm going to
00:15go ahead and do it from the command line, just so that you can see how that is done as well.
00:19So from the command line, I'm able to just talk to MySQL, saying mysql and then
00:24-u for user and root. So it's a root password. So you are going to need to
00:30know your root password for MySQL. Now, if you followed me in the Essential Training,
00:34the password we set up was OtlPHP07 and that was the password we had set up.
00:43If you have forgotten your root password you can go to the MySQL
00:46website and there are instructions there for how to reset it and you'll want to
00:50follow those. But if this works for you, and you're inside MySQL with root and password,
00:55then now we have the ability to create new databases, because we're logged in as root.
01:00So creating a database is easy. The caps that I'm typing for create database
01:05are not essential; this is considered good MySQL practice just so that it
01:09makes it really clear the difference between the MySQL commands and then
01:14the strings I'm passing.
01:15So create database photo_gallery, that's what I'm going to name it,
01:18got a semicolon at the end and that will create my database. If you are using
01:22phpMyAdmin, you will then want to click on that database to select it,
01:27and be able to keep working with it. If you are here, we have to type USE
01:32photo_gallery and that will sort of switch us in to the photo gallery.
01:36It will then know that's the database that we're working with. We have to type that USE
01:40at the beginning, and then I'm going ahead and just paste in some MySQL--
01:46you can pause the movie if you need to copy it down-- for the user table.
01:50Take a look there. I'm going to create the table users. I'm going to have an
01:53id int(11) NOT NULL auto_increment. We have seen that before. We're going to have
01:58a username. It can be 50 characters long. Password, it can be 40 characters long.
02:03First name, 30 characters long. Last name, 30 characters long. And the primary key
02:07will be ID. Nothing we haven't seen before. So now we have our database and
02:11we have our first table in there, USERS.
02:13That's where we're going to start, is working with our users table.
02:16The one additional step that I want us to take that we did not do in the Essential Training...
02:20In the Essential Training, if you remember, we just logged in as root
02:23all the time. That's a bad practice. We don't want our web application to be
02:27logging in as root. Root really should be reserved for the times when we want
02:31to log in and do these kinds of special operations.
02:34So instead we're going to create a new user and the way we do that is by typing
02:38GRANT ALL PRIVILEGES on and then the name of database .*. That's the wild card
02:45to say everything that is on photo gallery, grant those privileges to and then
02:50inside single quotes, the name of the user that you want to make it.
02:53I am going to make my user called gallery. You can call it photographer.
02:57You can call it your first name, it can be anything, but the key here is it not root.
03:01@ and then go ahead and put 'localhost' again.
03:05So in between those single quotes localhost and then identified by and
03:10I decided that my password for this user will be phpOTL123.
03:16So you can make it something else if you want, just make sure that you remember it,
03:19write it down, but phpOTL123 is what I'll be using and just by issuing now
03:24one command, it creates the user. So the user_gallery with the password
03:28phpOTL123 now has access.
03:31So that's all we need to do in MySQL for now. So I'll go ahead and type quit to
03:35get out of that and let's switch back to our photo gallery and I'll open up
03:40TextMate and will start a new file and if you remember before we had a config file
03:45that we put in our includes. We're going to do that again. config.php
03:50and this will hold our configuration information.
03:53So if you remember what we did in the Essential Training, we set up some constants,
03:56some database constants, and these are the ones that we had set up
04:00that I have just simply cut and pasted in here. We're going to,
04:02obviously, want to change those now for our new user to gallery and to
04:08the password phpotl123 and our database now is just going to be called
04:14photo_gallery.
04:15There is one additional change that I want to make here. When defining a constant,
04:20a constant can only be defined one time. We have talked about that before.
04:24So it's a good practice to always keep get in the habit of whenever you are
04:27defining a constant to check and see whether it's already defined or not.
04:31It makes it very error resistant.
04:33So the way we're going to do that is by checking to see if it's defined.
04:38So we can do if (notdefined(DB_SERVER)) and then we could put our brackets around it
04:49and now it's like an if-then statement.
04:51So if it is not defined, then define it. The more common way you will see this written
04:55is like this. They are using that ternary operator. So if it is defined,
04:59then return NULL, if it is not defined then define it, and that's the format
05:04that I want us to use here.
05:04So I'll go ahead and paste all those in, there we go. So again, if you need to,
05:09take a moment to copy those down, but make sure you understand most of what
05:13we're doing there. We're saying if it is defined then do nothing;
05:16otherwise take a second and define it.
05:18So, now we have our database, we have our user table, and we have set up the
05:22constants that we're going to be using to connect to the database.
05:25Now we're going to be ready, in the next chapter, to start creating the MySQL database class.
Collapse this transcript
6. Foundations of an OOP Project
Creating the MySQL Database class
00:00Now we have our project directories all setup and we have created our MySQL
00:03database, we're ready to start building the foundations of our object oriented project,
00:07the photo_gallery. We're going to start doing that by taking a look at
00:10the MySQL database class. The idea here is to take everything we learned about
00:14connecting to databases from the Essential Training and apply what we have
00:17learned about object oriented programming to it.
00:19Let's start by taking a look at those steps that we learned in the Essential
00:22Training. The very first step is that we'll require the config file that has
00:27those constants defined in it and then we have five basic steps. We're going to
00:30create a database connection, select the database we want to use, then perform
00:34the database query, use the returned data from that query and then close the
00:38connection. Steps 1,2 and 5 will be the same for our entire project.
00:42It's really steps 3 and 4 that will vary from page to page and we saw that also in
00:47the Essential Training. Now let's see how we can put these into an object.
00:50I am going to start by creating a new file and we're going to save that in our
00:53includes directory as database.php. Let's just open this up a little bigger and
01:00we'll just put it over here, so that we can see both at once. Now we know that
01:05we still are going to want this require. That hasn't changed at all. That will
01:09happen even before we define our class, which will be MySQLDatabase.
01:12Now you might be wondering, why I went ahead and called it MySQLDatabase and
01:19not just simply Database. Well, we could, but my thinking here is that
01:23if we had a different class for every database, then it would be really easy for us
01:27to swap out databases. So let's go ahead and when we're done, we're going to
01:30instantiate $database = new MySQLDatabase;. That's the idea.
01:38That's what we're going for here. That way, database is ready to go, ready for me to use.
01:43As soon as this file is done, it will not only define the class but create a
01:47new database and assign it a database. If I, for example, want to change it
01:52someday, I can have another one, that is, my OracleDatabase, or another one,
01:56that is, my MSSQLDatabase, for example. But for now, we're just going to use
02:01MySQL, but we already have that sort of modularity built in. We can even have
02:05something that looks in a config file to decide which one of my database
02:08adapters should I use. So I think this is just a good programming technique.
02:13Now let's start by taking step 1 here and let's think about how we can put that
02:16into our object. I'll just copy it and we're going to need to put it inside a
02:20method. So let's go ahead and say function, and let's call it simply
02:24open_connection. Let's paste all of that we just had in there. We don't need
02:30this 1 anymore. I'll go ahead and move this over and expand it a little bit, so
02:33you can see it a little better. There we go.
02:36So now, we should be able to call $database->open_connection and it would
02:45open a connection for us. That is what we're going for. So this is got to be a
02:48public function, we saw that. There is a couple of more things we need to do
02:52though, because just opening the connection doesn't do much. This sets a local
02:57variable, connection equal to the connection, but then we don't have access to
03:01it. So this is where we're going to need our attributes.
03:04So let's say we're going to have an attribute here. We'll make it private and
03:09we'll call it connection. That is where we'll store our connection. So we know
03:14then that we have to change these to refer to the instance variable,
03:17this->connection. So now it will create the connection for us and then assign
03:23it to that attribute.
03:25So now, whenever we want to talk about the connection, we can refer to it as
03:29database->connection. Then do whatever we want with that connection, except
03:34that it is private. So we're going to need another way to access it, the same
03:38idea as that bank vault and the bank teller that we talked about, but we have
03:41done a good thing by storing it because now it is part of the object and that
03:44connection is held on to.
03:46Now you may be thinking, isn't there an easier way to do these two steps?
03:49We learned about the construct method and sure enough, if we do function
03:54__construct, we can open the connection automatically. So now we don't even
03:58need this step. As soon as we create the database object, it creates the
04:02connection for us. So we can already start to see how we're going to put all of
04:06these database connection parts into our object.
04:10Let's fold these up and now let's try creating another one here for public
04:16function close_connection. That should be obvious enough. We'll just come
04:22down here and grab these from step 5. Of course, we're not looking at just
04:28connection anymore, now we're looking at this->connection, the attribute. So
04:34there we are. Now we have brought in close_connection. So that's all there
04:37really is to taking those kinds of function and putting them into an object.
04:42Now we have the ability if we wanted to say $database->close_connection. Now
04:51it will open the connection when it creates it. Then in the next step, it will
04:54close it. It will still be able to find the connection because it's held in
04:58that instance variable.
04:59Before we leave this, once we open the connection, we also know that we're
05:02always going to want to the step 2 here. That is going to happen every time. So
05:06let's go ahead and copy that and let's go ahead and perform that at the same
05:09time. We're going to put it in the else statement. So if there is no
05:13connection, then die. But if there is a connection, then go ahead and select
05:17the database, this->connection, write actually to make that little change.
05:21If there is not a database selected, then die also. But if there is,
05:26then just keep going.
05:26So now we have both our open and our close connections. So I'm going to go
05:32ahead and take this out. We don't want to close it. We're going to want to keep
05:34it open because now this is available to us. All we need to do is refer to the
05:39object database on any page that has included this database.php file and
05:44we have full access to our database. You may want to call this just db.
05:48That is very common. Or we also saw that you could do db = &database and that will
05:56point it to the reference. You could also refer to that same MySQL database
05:59object by just using db. I'm going to use database all the time, but I'll go
06:03ahead and leave it there, just so that you have it.
06:06In the next movie, we'll continue building our database class by looking at how
06:09we can put in step 3.
Collapse this transcript
Adding queries to the MySQL Database class
00:00In this movie, I want you to take a look at how we can get our MySQL database
00:03class to actually perform database queries for us. Specifically, I want to
00:07focus on step 3 out of our five connections on performing database query.
00:11The SQL is going to change each and every time on different pages.
00:14We're going to want to run SQL on different tables, we're going to want to ask for
00:18different things, we're going to want to inserts and deletes, but this part
00:21here is the same every time. We're just simply doing a query, getting the result back
00:26and making sure the result exists.
00:28So let's take that and put it in our class. I'll just copy it and paste it over
00:31here in our class. I'll go down here and we'll make public function query.
00:39Of course, we're going to pass in ($sql). Then let's just paste in that same code
00:44we were working with. Now we know we're going to need to ask for the connection
00:48as the attribute from MySQLDatabase class.
00:52Then the one other change we're going to need to make here is, of course, if
00:54there is not a result, die, but otherwise, we want to return the result. It
01:00doesn't do us any good, if we just run the query and then nothing happens.
01:03We want to be able to return it out of the object and then we'll be able to catch
01:07it into a variable. Then we'll be able to work with those results.
01:11In the Essential Training, we all saw you had a couple of other helper methods
01:14that we were using to help us interact with databases. confirm_query was one of
01:18them. I'm going to go ahead and bring that over into our class. You will see
01:23that it does the same thing that was being done up here. So we can actually
01:26take all of this, now that we have a new method for it, and reduce it down to
01:30just confirm_query. Then we'll pass it in the ($result).
01:36Now this can actually be a private method because it is not something we need
01:40to be able to call from outside the class. The class just needs to be able to
01:44confirm that the query has worked. Now if you ever came over with a case where
01:46you did want to be able to do it, you could make it into something public.
01:50I'm just going to change this also from $result_set to just $result. I think that's
01:54just a little cleaner.
01:55Then the other one that we were working with before was this mysql_prep.
01:59If you either didn't do the Essential Training or if you don't have access to that
02:02code again, go ahead and pause your movie, copy this down but remember what it
02:05does is it prepares values for submission to SQL. It does that by doing some
02:10checking to figure out whether or not magic quotes has been set, whether or not
02:13we have access to mysql_real_escape_ string. Then it does some processing on the
02:18value that we submit. So it is a good way to just make sure our values are
02:21clean and ready to go to SQL.
02:23So I'm going to copy that one as well and I'll close that up. Let's put that
02:27one up here, mysql_prep. Even though we don't have a place that we're going
02:32to use it just yet, we can see right away that it makes a lot of sense for us
02:35to have any code related to mysql be inside our database class. We're grouping
02:40our code, so it is easy to know where to find it. We don't have to wonder which
02:43one of our function falls in it, it is in our database file, makes it easy to
02:47find. Then we can modify this later, if we need to. I'll go ahead for now and
02:51let's make it public.
02:53So now we have the majority of the parts that we were working with in the
02:55Essential Training rolled into our database class. We can simply call query
02:59on some SQL and it will take care of the rest for us. So let's try that out in
03:03the next movie and make sure that our database class is working and
03:06troubleshoot any problems that we run into.
Collapse this transcript
Using the database object
00:00Now that we have a database object that's able to connections and perform
00:03queries, we need to try it out and make sure that it's all working.
00:07So we'll just do that in a really rough way. Open up index.php and we'll put some code here,
00:12so that we can try it out.
00:13Now the first thing that we need to do is we need to load in our database code.
00:17Now if you look over here in the directory structure, you will see the
00:20index.php is the file that I'm working in. That's inside public. I need to back
00:25a directory, so that I can then go inside includes and load up database.php.
00:31We'll do that with require_once("../ includes/database.php"). That will load in
00:41the database file. So that will define my class and it will instantiate the
00:46database very well for us, so that we can work with it. We just test that real quick
00:50by doing a simple if database is set, echo "true". If not, echo "false".
00:54So that's the only thing that's happening on this page is that it loads in database.
00:58So there's no other way that it can be set. Let's just try that. I'll go into
01:02Firefox and for me, that's going to be localhost/~kevin/photo_gallery/public.
01:05That's where we want to be, index. php. Now you may not need to put the
01:15index.php, if your server is set up to automatically serve PHP index pages.
01:20If you are on Windows, of course, you won't need to put in the ~kevin at the beginning.
01:24Now we can see that result is true. That's the important part. That it came
01:27back and it said, yes, it was set. Great. So let me just switch back now to
01:33index.php. Let's try one of our other methods. Instead of echo "Is this working?"
01:38I'm going to try echo and then ask our database object that we have
01:42created to run its mysql_prep method. It's going to run it on a string. That's
01:46what it does. It works on values. So it's just a simple string and
01:50it's ("its working?<br/>").
01:53Now the important part is this apostrophe. SQL doesn't like apostrophes because
01:58it uses apostrophes when it's constructing its values and that's what we need
02:01to escape. So what we're wanting to see ismthat apostrophe. Does it get
02:05escaped? So let's just save that, switch back to Firefox and sure enough,
02:09there's the slash in front of it which makes it acceptable for SQL. We can now
02:13use that. That value has been rendered safe for us.
02:16So those are the most basic tests we can perform. We made sure that the object
02:20was loaded in successfully, no problems there, instantiated to a variable, so
02:25we saw the database is set, and we were able to call one of the methods on
02:28that, so we're able to see that method works. So we know our basic object is
02:31working. If not, go back and double check. Make sure that all your parenthesis
02:35and brackets and everything are all closed properly. If they weren't errors in
02:39there, this is your chance to troubleshoot.
02:40But I'm going to keep moving and I'm going to go ahead and try doing some SQL.
02:44I just need to open this a little wider. I have just got some real basic $sql
02:49to insert into my users table the values, id, username, password, first_name,
02:54last_name and the values will be 1. And then the string for my username, which
02:59I'm just going to make 'kskoglund.' You can make it whatever you like. My
03:02password, I have made just 'secretpwd' and then my first_name and last_name.
03:06You can put in yours. Then all I'm doing is telling the database, run that query.
03:10That should perform the insert.
03:12Now normally when we do inserts, we do more error checking to make sure it was
03:15inserted and everything. Right now, I'm just doing a really primitive check to
03:19see did it work. One way that we can test that, without going into php.myadmin,
03:24is just to search for that value and see if it's there. So run another sql
03:29statement "SELECT * FROM users WHERE id=1", tell the database object to run its
03:36query method on that sql. It's going to set that variable, $result_set, equal
03:40to the value that's returned. Remember, we had it return a value back to us.
03:44Then it's going to run mysql_fetch_ array on that result_set to get the first
03:48user. Then from that user, return the username. Let's try it.
03:51Now I'm just going to run this once because I want to insert into the database
03:55only once. There it is. It worked. Now if I try it again, you will notice that
04:02I get a database query problem, because it isn't able to insert it into the
04:06same id multiple times. So if you ran into problems there, you will want to go
04:10into mysql and remove that entry and then try again. Or you can simply take
04:15these three lines here and comment them out, so that we only insert in one
04:18time. After that, it runs without a problem. We can make sure that we're
04:22getting back users.
04:23So if all of that works, we know that our database is working.
04:26While we're looking at this, I want to point out something to you. We have talked about
04:29making our code that was basically database agnostic, that it didn't care
04:33whether or not we had mysql or oracle or whatever. We can see our code here is
04:37actually asking for mysql_fetch_array. That is definitely mysql thing and
04:42if we switch databases later, that's going to break for us. Even though it's one of
04:45the methods we defined, we did the same thing up here when we said mysql_prep.
04:50We said that we were prepared for mysql, but if we change to oracle database or
04:53something later, then that obviously isn't going to make sense.
04:56So let's make improvement to our object. In addition to these methods here,
04:59let's add another one. I'm going to put it right above the private method and
05:03I'm just going to call it public fetch_ array. All I did was take mysql out of
05:07it, but that way we could have an oracle adapter, which would do fetch_array,
05:12and it would do it in a different way. It might have a different way of
05:14handling it that makes it agnostic. Then all it does is return the result of
05:20mysql_fetch_array on the result_set. Now we just say okay, database object go
05:27ahead and perform fetch_array on the result_set.
05:30For changing mysql_prep, let's just change this now to instead be escape_value
05:35instead. We'll come back over to our database object and we'll do the same
05:40thing. Instead of mysql_prep, it will just be escape_value. Now escaping the value,
05:45you can happen in whatever it needs to happen for whatever database we're on.
05:49There are three other database neutral methods that I want you to go ahead and
05:53input here as well. We aren't using them yet, but let's go ahead and put them
05:55in here so that we're ready. We have looked at them before. We have got
05:59num_rows, which performs mysql_num_ rows and returns how many rows are in a
06:03result set. We have got insert_id, which returns the last inserted id over
06:08the current database connection. That's mysql_insert_id. We have seen that before.
06:13mysql_affected_rows, how many rows were affected by the last thing.
06:17Each time we're just dropping mysql off to front of it. Those are going to make
06:20for nice database neutral methods. If a database adapter needs to be swapped
06:24in, so that we're using a different database, our code doesn't break.
06:28We don't have to do a massive rewrite. We have already taken that into account
06:31when we wrote our database object. So let's go ahead and save that.
06:34Let's just make sure that it's all working. Sure enough, everything is still working fine.
06:38In the next movie, we'll take a closer look at how working with this database
06:42as an object is actually an improvement over the functions that we were using before.
Collapse this transcript
How OOP is an improvement
00:00Over the course of the last several movies, we have been able to take all of
00:03our database functions that we were using before and put them into a database
00:06class. In this movie, I want to just take a brief look at how that object
00:10oriented programming approach is actually an improvement over just having those loose functions.
00:14Now you've probably noticed some of the advantages to using an object oriented
00:17approach as we're going. For example, we were able to group all of our code
00:21together. So things like mysql_prep, which became escape_value, those can be
00:26grouped with our database. So all of our code for our database is in one place.
00:30We also saw how it makes the code modular. We would be able to potentially swap
00:35in a different database, if we needed to. We were able to write methods like
00:39num_rows, which calls mysql_num_rows, and therefore allows our code to be
00:44database neutral.
00:45One thing that we didn't explicitly talk about though is that improvements made
00:48to this object are now available on every page where the object has been
00:52instantiated or where it's being called. So suddenly, by adding the method
00:57num_rows to our object anywhere in our site that we were calling the database,
01:02we now have the ability to call num_ rows. So any improvements or complexity
01:06that we add to our object automatically propagates out to that object every
01:10time that it's being used throughout our site.
01:12Let's make another kind of improvement like that now. Let's add a new public
01:16attribute which will be called $last_ query. It will allow us to find out what
01:22the last query, we tried to run, was. Now in the past, we have done this using
01:26just an echo statement and that was a really good way to debug.
01:29Now we can actually just make it a part of query. Whenever we run a query,
01:32we can just set this->last_query = $sql. So we'll just set that value each and
01:40every time, so we can always just ask this object, Hey! What was that last
01:43query you ran? One other place that we can put that is in our confirm_query method.
01:47So let's come down here to this private method and let's just alter it
01:50slightly. Instead of just dieing with this simple text in the sql_error, let's
01:56have it construct a string out of that same string, but then also add the last
02:01SQL query to it and then die using that string. So let's save it.
02:05In order to try this out and see how it works, one easy way to do it is first
02:08to come back over to our index page and let's just take out these comments
02:12where we got that error before, we'll save it, we'll go back to Firefox and
02:16let's reload the page. Database query failed, we got the same error but
02:20now we also get Last SQL query. We can actually look at our query and see if
02:25we can figure out what was wrong with it.
02:26Now this must be something you only wanted in testing. Once we get to
02:28production mode, you might want to come back over here and actually just
02:31comment this out, so that it doesn't get appended anymore. That proves the
02:35point that I was talking about. That simply by commenting it or uncommenting
02:38it, it suddenly changes what happens throughout our website. It changes the way
02:42this object behaves.
02:44There is one other function that I think is right for some improvement.
02:47Let's jump up here to this escape_value. Now value might get escaped on a single
02:52web page, five, ten, fifteen different times. Before pulling in a whole lot of
02:56form data, we might be doing a lot of escaping.
02:58Every single time that this function gets called, it's going to check and see
03:02are magic quotes set. Does this function exist? Every single time. It occurs to
03:07me that that's wasted processing power and we're just slowing our site down.
03:11Instead, let's take these two lines and we'll just cut them. We're going to
03:14just jump up to the top of the document here. So I'm just going to paste those
03:18two checks that go on right here. I'll take the comment out. I don't need that
03:22anymore. Instead of new_enough_php, I'm just going to rename it as
03:27real_escape_string_exists. There we go.
03:31What I want to do is set attributes equal to these. So each of these are just
03:35going to become this->magic_quotes_ active, this->real_escape_string_exists. So
03:40now what I need is to have those attributes and I'll make them private. There
03:43is no reason I need to get to them from outside the class. This one will just
03:47be called magic_quotes_active and this one will also be private and
03:54real_escape_string_exists.
03:56So stop and think about this for a second. What this means is that now, down
03:59here at the very bottom when I instantiate the MySQLDatabase class, one time
04:04and only one time it runs the construct method. That will check to see is magic
04:09quotes active. It will save that value here. It does the same thing for
04:13real_escape_string.
04:14So we don't have to waste the processing power checking that each and every
04:18time. Now we have those attributes that we can check. So instead, let's just
04:23copy this one because we have changed the name. So now if we check that
04:27attribute and it's true, then perform the same thing. We'll just put this-> in
04:34front of magic_quotes_active. Then here we can also put this-> in front of
04:38magic_quotes_active.
04:39So now, it does the same escape of the value that it did before, but it doesn't
04:43have to waste the processing power each and every time. Come back to the
04:46original point that I was making, these changes now propagate out to anywhere
04:51that we were using the object. I feel like we have a pretty good database class
04:54now. Some people like to go ahead and populate this database class with all of
04:59their database calls and everything, but we're not going to do that. Instead
05:02what we want to do is create a separate user class. We're just going to make
05:06use of the database class, whenever it needs to access the database. But it can
05:10have a lot of other things that are unrelated to the database in that class as
05:13well. So we'll work on the user class in the next movie.
Collapse this transcript
Creating a User class
00:00Now we have a pretty good database class that will connect the database for us,
00:03I want us to write our second object, which is going to be our user class, and
00:07the user class will make use of the database class to connect to the database,
00:11and all the information about finding users will go in our user class.
00:15Now we could put those in the database class, in fact some developers do,
00:19but the database class might start to get quiet large if we have a lot of different
00:22finds going on. Instead since these belong to the user, they are unique to the user,
00:26it makes sense to put them there to group our code according to the user object.
00:30So, I'm just going to open up index.php here. What we want to do is try to move
00:35these three lines of code into a class, so that all of that finding is handled
00:41by the class. And instead what we'll end up with is something kind of like this.
00:45Now I'll just put dot, dot, dot for now. So basically the found user will
00:50ask the class to do something and return to the found user. In one line, that's it,
00:53and then we can start to pull information like username out of it.
00:57So let's create the class and figure out how we can call it to return that found user.
01:01I am going to create a new file in TextMate and I just go ahead and save that,
01:06and I'll name it user.php, singular. Then I'll put our php tags and class User,
01:14singular. That's the way we want to do objects is with singular name.
01:19If we had many of them there would be users, but the singular version of the class is just one.
01:23It's also a good idea at the top here to go ahead and require the database,
01:27because we're going to be needing the database, so that user can make those calls,
01:31and even though back over here in index, we're still saying load
01:36the database. It's okay to do it with require once a second time, because
01:40it will say, "Oh! I've really done that and it will skip it." But since it's
01:42a dependency of the class, it's a good idea to go ahead & have it here at the top.
01:46It's just smart programming.
01:47Now inside my class, I'm going to go ahead to paste two methods, which I think
01:51is will look very familiar to you. The first one is find_all and you will
01:55notice that I'm using global to pull in the database, so I can work with it.
01:58We talked about global. It brings in the database variable from the global scope,
02:03so that we can use it. Then I'm going to ask that database to perform a query
02:07for me, and here's my query. Just simply find all from users. That returns a
02:11result set and I simply return the result set back to whatever call this method.
02:16The second is find_by_id. It's basically the same thing, except that
02:18it takes an id. The SQL is slightly different, and it goes ahead and
02:23does the fetch_array on the result set. We're going to have to do that up here.
02:26We're going to have to perform fetch_array each time we go through and fetch a new array,
02:30but if we're only returning one, there is only one object inside this wrapper,
02:34there is no sense in returning both the object and the wrapper.
02:37Go ahead and just take it out of its wrapper and hand back just the array that
02:41we'll work with. So I had just called it found for now.
02:44So I'll save this file. There are two ways that we can go about this and I want
02:48us to see both of them. The first, I want you to notice that this right here is
02:54an instance method. We talked about the difference between instance methods and
02:57static methods or class methods earlier. This is an instance method,
03:01which means in order to call it, I need to have an instance.
03:04So before I can call found user, I've got to say User = new User,
03:11just to have an instance of it, and then I can ask that instance capital User,
03:16find_all. That will then find that user or if I wanted to find just one,
03:22let's do that instead. That's a better example. Find_by_id(1). So I have instantiated it,
03:27and then used that instance to call this method that returns it.
03:31Now a lot of times you will see programmers do it this way. Now there is
03:35nothing that's inherently wrong about in doing it this way. If you prefer this way
03:39or if you are used to doing it this way or maybe someone else's code is
03:42done that way, it's not necessarily wrong. However, I think that the better way
03:46to do this is to use static that we talked about before and make these into
03:51class methods.
03:52The class method, the difference is that the function sticks around,
03:55that's static, it sticks around even when we don't have an instance.
04:00So we no longer have to instantiate. Instead we can use our double dot notation and
04:05just ask the class directly, "Hey class, run your find_by_id method" and
04:10it returns the value found_user and then we can do the username on it.
04:13Let's go ahead and try that. Let's just put in echo hr tag here,
04:18just to separate it, and let's load up Firefox.
04:22Let's hit Reload. Oh! Class User not found. That's because I didn't include it up here.
04:26So I'm also going to need to of course require_once user. That was a
04:32silly mistake on my part. Let's just go back to Firefox and try again and there we are.
04:36So if we step through what happened here, the database class was defined then it was
04:41instantiated and assigned to the variable database. Then we define the user class.
04:46When we get down here, we've used the static method to search the database to
04:52find id 1. It return to that and then we're able to say all right give me
04:57your Username out of your row.
04:59You can also try our find_all method. You could take a look here. Just going to do
05:04another static call to find_all, return to the user sets. We'll then need to do
05:10a database fetch array on each one and return it to the value user and then go through each one
05:15and list the Username, First Name, Last Name. You can pause it if you need
05:18more time to copy that down, but I'm going to go ahead and try it out.
05:22Switch over the Firefox and there we are. Username: kskoglund, Name: Kevin
05:27Skoglund. So with a very small amount of code in our class definition,
05:31we were actually able to clean up all of these messy SQL that was going on here
05:36and make it something nice and clean. User find by one. It makes it really clear.
05:40It's a good narrative to our code.
05:42I'm going to make one more change here. I'm just going to paste in another
05:46function, which is find_by_sql. So this will just take any SQL we send it and
05:51perform that on the database. That's a useful one to have, because we might not
05:55always want to just find a single one or find all of them; we might want to
05:58find a subset. So find_by_sql might come into use in that case. In fact,
06:03on your own what I would like you to do is rewrite find_all and find_by_id so that they
06:09use find_by_sql. Keep in mind that they are static methods. So you want to make
06:14sure that you call it statically.
06:16Then in the next movie, we'll look at how we can improve this class further by using
06:20instantiation on the results that come back from the database.
Collapse this transcript
Instantiating user objects
00:00We created a user object, but so far our user object has really just been used
00:04as a way to find records in the database and what we have been returning are
00:09arrays just rows of data and not really working with objects, working with them
00:14in an object oriented way. So in this movie I want to just see how we can
00:17further improve our code by doing that. First let's take a look at the results
00:20of the assignment I gave you at the end of the last movie just to make sure
00:23we all are on the same page.
00:24We introduced find_by_sql as a static function and what I want you to do is to
00:28modify find_all, so that it also calls statically find_by_sql and we can just
00:34simply return the result of that. That will return whatever find_by_sql gives us.
00:38So effectively it's just the same except that we're providing the SQL for it,
00:42find_by_id is slightly different. We're going to do the same thing, we're going
00:46to call it statically, but again we're going to use that fetch_array to reach
00:51in and return that first row of data out of the result_set.
00:55Now this raised an interesting point for us. What we're actually returning here
00:59when we do fetch_array is an array, it's not an object it's an associative
01:03array that has keys and values that represent a row in our table. Let's go back
01:08and look at index.php and see -- actually let's go at the top here I'm just
01:13going to delete a lot of this code we don't need this anymore.
01:16So if you will notice where I'm doing find_by_id, I'm getting a found_user, but
01:21I'm not actually getting a user. What I'm really getting here is a record
01:26that's what coming back to me is a record or row.
01:29So I'm going to just change this to record to make that clear and what I really
01:32want to do is be able to work with this as an object because we really want to
01:36be doing object oriented programming and the reason why is so that we can
01:39perform more complex tasks with an object than we can with just simply text
01:44that's in an array. There can be a lot of complexity built into objects.
01:47Here is a good example of that. Look down here where we have user first_name
01:51and user last_name. It's a very simple case but it would be great if we can
01:55have something that's we just called user full_name and there was a method in
01:59our object that we would simply look at the first_name and the last_name and
02:03put them together for us.
02:05That's something that's very common and we would get some benefit out of being
02:07able to just call full_name and have it take care of the rest and there are
02:11certainly more complex cases as well, we could have it pull together at
02:15someone's mailing address and maybe it checks another database here and another
02:19database there while it's constructing that for us. There can be a lot of
02:22complexity behind that. Well in order to do that what we really get to is the
02:26point where we can go from our record to actually having an object and that
02:31object would have an attribute like username.
02:34So username would just be an attribute. So let's go ahead and add that
02:38attribute over here to our user model. So we'll just make public and then
02:43username. In fact while we're at it let's go ahead and put in our password, our
02:47first_name and our last_name as well, so that all of those attributes are
02:51there. And let's not forget that there is one other column in our table, which
02:54is the id column. Let's go ahead and save that as well. Basically every column
02:58that's in our MySQL table has an attribute.
03:01So what we can do is when we bring that row out of the database, we'll just
03:05take a second and we'll assign all those values to their correct attribute. So
03:10let's save this and let's switch back over to index and let's do exactly that.
03:15We're going to need a user object. So we can't forget to instantiate a new
03:20object but we don't one have yet.
03:21So new User, now we have an object and now we can perform those assignments. So
03:28let's do the first one here user_id is going to be equal to the record and
03:35we're looking for it's id in the array just to save us some time, I'll go ahead
03:40and cut and paste the other ones in there. Remember that you can pause the
03:43movie if you need to it to have a little more time, but this will then give us
03:47attributes that we can work with.
03:49Let's save this and I'm just going also comment this out. I can do that in Text
03:53Mate with Command and the forward slash and that will just give me quick
03:57comments on those. You can also cut and paste them out, or type them in by hand
04:01and let's just switch back to Firefox and try it and there it is.
04:04Now this is no longer just an array, it's actually an attribute of an object.
04:10Just so we can make very clear why that's useful, let's switch back over to our
04:14model. I'll close these up, so they are out of our way and I'm just going to
04:18add a new method here called full_name. So you can take a second to copy that
04:23down but what's it's doing it's checking to make sure that first_name and
04:25last_name are set and if they are it returns the two together.
04:29So I'll save that, let's come back over to this page and now instead of
04:34username let's ask for full_name and we have to have this parenthesis to let it
04:39know that it's a method name that's the difference. This would be if it was an
04:41attribute this is a method. Let's go back to Firefox and voila!
04:46Now instead of doing something clumsy like this every time we want to put
04:51together the first_name and last_name, we can do simply this. So this is
04:55getting as closer to an object oriented approach, but just like before when
04:59we had all of our raw SQL sitting here and we turned it into the find_by_id
05:03method, we can take all of this and actually push it up into the object as well.
05:08An object should know how to build itself.
05:11And we can do that by creating an instantiate method. So I'm just going to cut
05:15all of that out of there and go back over to my model I'll fold up this method
05:21and let's make a new method. This is going to be a private method. We don't
05:25need to be able to access it outside. We'll just let the class be able to
05:29access it and we'll make it static, function and we'll call it instantiate. And
05:36it's going to take as its argument a record.
05:39I am going to paste all that old code in there and of course instead of user
05:45now I'm just going to make it object just so it's a little clearer that that's
05:49what we were creating here is an object. And these are all still fine, I'll
05:54just do a quick little cleanup on it so these rows look nice and clean it's
05:58nice. It's nice and organized then and instead of user I can refer to it as
06:02simply self.
06:03So create a new version of yourself and instantiate yourself and in the very
06:08end once we have done assigning all these attributes then we just say return
06:13object. That will now instantiate an object for us.
06:17Now in the next movie we'll see how to make our find methods work with this
06:21instantiation, but I want to look at the couple of improvements we can make
06:23here first. The first is that I just want to know that we could do some
06:26checking the record actually exist and that it is in array before we start
06:29doing that. That's not a bad idea.
06:30So the second thing is that this is a simple long form approach. You can see
06:34that if we had a table that had let's say 50 different columns in it then
06:38we would have to list all of those out here and that's a little bit tedious to do.
06:43So another way to do it instead would be something that's a little more
06:47processed, a little more computer savvy. We'll loop through each of the
06:52attributes and what we'll do is we'll just check to see does that object have
06:57an attribute? This is has_attribute. This is something that we're going to have
07:00to write. What we're going to do is true or false, does it have that attribute?
07:04And if it does had the attribute then assign it that value and return that
07:08value to it and I think that's a better approach.
07:10So I'm just going to comment out the short form approach, so that what we were
07:13using is the longer form approach instead. So now what we need to do is write
07:18that has_attribute method. So I'm going to make it a private method and it
07:23won't be static, it would be a non- static method because I'm calling it on an
07:26instance, notice that has_attribute and then it will just be an attribute.
07:35So this is going to require us to use a new PHP function that we haven't seen
07:40yet which is get object_vars, I'll paste in there and then I'll just open this
07:44little wider so you can see. I have got some comments already including get
07:47object_vars it says what we're using and what it does is it looks at this instance
07:52that we're working with this and finds out what are all the attributes.
07:58Now one note here is it includes the private attributes. So just keep that in
08:02mind, it includes private one. You can look at php.net if you want to find some
08:05workarounds so that you don't include the private ones. For our purposes right
08:09now it doesn't really make a difference and then the next thing we'll check is
08:12array_key_exist does the key attribute exist in object_vars in the array that
08:19gets return back and that's going to be the has_attribute function.
08:22So this will then instantiate objects and then it will through all of the
08:26columns that are in our table, check and see if there is a matching attribute
08:30and if so, it will assign that value to the attribute and then we'll have an
08:35instantiated object because it will return the object.
08:38In the next movie let's see how we can modify our find methods to complete this
08:42so that they will automatically instantiate objects when they are finding.
Collapse this transcript
Revising find methods to instantiate
00:00Now that we have written an instantiate method in the last movie, in this movie
00:03I want to still revise our find method, so that they perform that instantiation
00:07for us. They never return rows. They always just return objects.
00:12Before we do that, I just want to correct something from the last movie, which
00:14is that I inadvertently commented out, $object = new self. We're going to need
00:18that down here. So make sure that the only thing that's commented out are these
00:21assignments. $object = new self still needs to be in that instantiate method.
00:26So I'm going to hide those and I'm just going to look at find_by_sql to start
00:31with, since that's what these other methods use. What we want to do here,
00:34instead of just having a result set and returning a result set, we want to take
00:39that result set and we want to process it. We want to go through each one of
00:42those rows by doing a fetch_array, pull back a row and then instantiate it.
00:47We will assign it to a new array. So I'm going to create an object_array here,
00:51just an empty array. Then I'm going to do my_sql->fetch_array on the result
00:56set, assign it to a row and then instantiate that row. Now it's going to be a
01:00static call to instantiate because that's a static function. The result will be
01:05an object that will just get added to the object_array. Then at the end, we'll
01:09return the object_array. So what we'll return is an array of objects and our
01:13rows and our result set will not ever get passed back to index, we'll just
01:17receive objects.
01:18So we'll save that processing. I'm just going to jump up to find_all and point
01:22out that we don't need to make any changes here. It's already just going to
01:25return whatever find_by_sql returns. So there are no changes there, but
01:29find_by_id is going to need to make a change because it was doing a
01:32fetch_array. So there is nothing to fetch anymore. If it's doing a find_by_sql,
01:36that's going to return a result array to us, not a result set. It's going to be
01:41just an array that comes back.
01:43So then what we're going to need to do is still pull that object out of the
01:46array. If it's the only one item in the array, we don't need to return the
01:50array, just like before. So instead, we're going to modify this slightly and
01:54I'm going to first make sure that the array is not empty. If it is empty, we'll
01:58return false. But if it's not empty, then we'll do array_shift($result_array),
02:03we remember array_shift from Chapter two, we're going to pull the first element
02:06out of the array. We could also just return the zero indexed element in the
02:10array, but I'm using that array_shift that we saw earlier.
02:12So that's the other change we'll need to make. Now this will also either be
02:15returning an object or returning false. The reason why we return false is then
02:19we have the ability to say if it returns something, so if we got something back
02:24and it will be either true or false.
02:26So let's go back over here and let's just make a modification to index now, so
02:29that it can make use of this. This one no longer be returning a record now.
02:33find_by_id will be returning a user and then we can ask for that user's full
02:38name. That's all there is to it. We have now reduced all of that code down to
02:42these two lines.
02:43Tell the object to find the item I want by its id and then tell that object to
02:48give me the full name back. All that complexity reduced down to those two things.
02:52Hopefully, you see now why object oriented programming is really powerful.
02:56We can make the same kinds of changes here to the user set. Instead when we do
03:00find_all, it's just going to return a set of users. So we won't be wanting to
03:04do a fetch_array on that anymore. Now it's just an array that we can loop
03:08through. So we don't have to use the while loop. Instead, we can actually just
03:12put in a for each loop. So for each users as a user, go through and output
03:17their user name and their full name.
03:18Let's try both of these out. I'm going to save it. We'll go back to Firefox.
03:22Let's hit Reload and there we go. So notice how much cleaner and more intuitive
03:27what's happening in indexes now. It's a lot easier to see what's going on and
03:31all of the complexity is pushed up into the model, so that it's still
03:34accessible but it's out of the way and grouped with everything else, so we can
03:37still find it, if we need it.
03:38So now that we know how to instantiate objects and have it happen behind the
03:41scenes, it's going to make it a lot faster for us to program our pages, pages
03:46like index.php, so that we can do what we want and all the complexity just
03:51happens for us automatically.
03:52In the next movie, I want to take a slight detour and talk about the case in
03:55which we haven't actually required the model that we're looking for in a
03:59special way that PHP provides that we can handle that.
Collapse this transcript
Autoload: The undeclared object safety net
00:00In this movie, I want to make a slight digression to talk about autoload.
00:04I'm calling it the undeclared object safety net and you will see what that is.
00:08You will see that it basically saves you if you have undeclared objects.
00:11Now first let's see what the problem is and then we'll see how to solve it.
00:14Let's say first of all that I did not have require_once
00:17(".../includes/user.php"). That's a necessary step for us to have user defined,
00:22so that we can use it here. Let's just try and loading that up without it.
00:25I will reload the page, Fatal error: Class 'user' not found in and it tried to
00:31find it inside this file, inside index.php and it says it was never defined.
00:36Now, of course, if you are a good programmer, you are going to want to always
00:39use this require_once, but I want to show you the safety net that can help get
00:43you around it, if that's not the case.
00:45Let's open up our functions.php file and we have got a few functions in here
00:49already. I'm just going to fold those up so they are out of our way.
00:52We're going to add a new one and it is this autoload. It's __autoload. Now that
01:00has the same format of the __ as we did for our constructors and destructors
01:05and clone, but it's not inside an object. It's just a standalone function that
01:09exists outside of an object.
01:11Now, of course, if we're going to make use of it, we have got to also make sure
01:14that we require our functions in here. Functions, so that we actually have
01:19access to it. So now autoload will have been defined, when it gets to the point
01:24where it says, oh user, that's not the find, I have an error. It will stop and
01:28first check to see is there an autoload function defined and it will call it
01:34and it will ask it basically, hey, what should I do? It will pass in as an
01:38argument, the class name that it's looking for. In this case, USER. So then
01:43we can provide instructions on what it should do to handle it.
01:47So I'm going try just making some simple instructions here. I'm going to say
01:51take the class name, make it all lowercase, then put php at the end,
01:56see if the file exists and if it does, require it and voila! The problem will be solved.
02:01If not, then die with an error that says the file could not be found.
02:06In that case when it's not found, we'll get something that's prettier than the ugly
02:11error output we got before.
02:12So let's try it now and see if that works. We'll switch back over to Firefox,
02:16the file user.php could not be found. Well, that's because we have to tell it
02:19where to find it. So in this case, this function is actually looking from
02:24index.php. So I'm going to have to put a .. includes/ to get into the right
02:31directory where that class might be. So that's going to be my includes
02:34directory. That's where everything is. Let's take a look again to see if that works.
02:38Now it works fine. That's why I have called this path. This is going to be the
02:41path that it takes to get there. We're going to work on this a little bit
02:45later, we're going to talk more about paths and we're going to refine it a
02:48little bit, but for now, this will tell everything that's in that root
02:52directory of public, how to find it.
02:54Now we're going to run into a problem, of course, if we're not in the root
02:58directory. If we're in a sub-folder or something like that, we'll have to have
03:01another way to navigate to this. We'll explore that a little later, but for
03:05now, I want to emphasize the autoload function and let you see that having
03:09this base function defined, we'll tell PHP how we can handle it.
03:14Instead of user, let's just try making up another one. Let's say $junk = new
03:23Junk, which doesn't exist of course. Let's go back to Firefox, The file
03:29junk.php could not be found. So we get something nicer than that old error
03:33message, but the main point is that autoload gives you a safety net for cases
03:39when it hasn't been defined yet.
03:40Now I know you are all going to be good programmers and you are going to go
03:43ahead and define it anyway, but it's nice to have this here, so that it can
03:47actually find and you could have several directories. Maybe it looks in five or
03:50six places to see is it here? Is it here? Is it here? If not, then finally
03:55fail. It can be as complex as we want, but it lets us have the opportunity to
04:00try and sort it out before we just get in there.
04:02Now in the next movie, let's take a look at how we can build a class that will
04:05handle our sessions.
Collapse this transcript
Creating the Session class
00:00Now that we have a database class and a user class, I want us to move further
00:03along toward the goal of being able to log in to an Admin area by looking at the session class.
00:08Now we took a look at sessions before in the PHP with MySQL Essential Training.
00:13I want us to now look at it with an eye towards making it object oriented.
00:16So to start it with I'm just going to go to TextMate and open up a new window and
00:21I'll save this in the includes folder and we'll just call it session.php and
00:28we'll start with our php tags and it's going to be class Session.
00:32That's going to be our session class that we're going create.
00:35Now if you remember back to what we learned in the Essential Training
00:38the session is going to be maintained on the server as a file. And what we're going
00:43to do is actually get the cookie for the session automatically sent to us by the
00:48browser and we'll be able to look up what file is there and then in that file
00:52we can store things and that way we can actually store that user state.
00:56And that's especially useful for things like whether or not they are logged in,
00:59because we can remember, hey, this person has been logged in already because
01:02I already found their id and I already marked them in my session file.
01:06So every request they make, we just check the session file. We don't have to go
01:10back to the database and say look up this user, see if they exist and see if
01:14they are authenticated and if not get their password and so on. We can just
01:19keep them logged in. The analogy that I used before was like having a nightclub
01:23and having a bouncer that keeps people out, but if you have a handstamp then you come
01:26and go as you like.
01:27So before we get started I just want to put a note here at the top, which is
01:32that I want you to keep in mind when you are working with sessions that it's
01:35inadvisable to store database objects in the session. You can store the id for
01:40the object so that you can go find it again, but you don't want to actually
01:42store the entire object, and the reason why we do that is because the objects
01:46that are in the session can become stale. That is that the database can be
01:50updated by other users on the system while the session still has an old version
01:54of it saved in that file. There also can be pretty large objects too and that's
01:58another reason why you don't want to put them in there because there are large amounts of data.
02:01It's much better just to store the id for let's say a users record and then go
02:05back to the database to get a fresh copy whenever we need something from it.
02:09So like our database class we're going to want our session class to exist right away.
02:13So I'm going to do the same instantiation at the bottom of the file that
02:16we did for the database class.
02:18So when this loads it will define session and it will create one for us
02:21automatically.
02:22So that means that a lot of the setup that we're going to want to have happen
02:25is going to take place in our construct function. If you remember back to what
02:30we learned in Essential Training, the main thing we need to get the sessions
02:34rolling in PHP is session_start. If you issue that PHP command it gets the session started.
02:40It figures out the cookie and it binds the session for us.
02:44So that that's all taken care of and if there wasn't a previous session,
02:47then it creates a new one. Other than including this session file in our index file,
02:51this is actually all we need to get session started. It's that simple.
02:56We basically have just said all right, make a new session object and when you make
02:59that object, get the session started in PHP and now we're ready. We have sessions,
03:03they are available to us and we can start working with them here.
03:06But because it's an object now we're going to want to have attributes,
03:09so that we can keep track of things.
03:10So for example I'm going to want to keep track whether someone is logged_in and
03:15I'll have a flag for that. Another one is the user_id. I'm going to want to have
03:19a flag for that.
03:20Now the user_id is going to be public. Someone would be able to ask the session for it,
03:23but logged_in I'm actually going to make private. So that only
03:27the session can figure out whether someone has been deemed logged in or not.
03:31That's not something that we can change the value of on our own.
03:34So from our application we can't just say logged_in true, logged_in false. Now,
03:38we certainly could do it that way, so that we just handle it from outside the session,
03:42but again we're trying to push all of the complexity about logging in
03:45everything into this session object.
03:47So I'm going to create a new function here called check_login and that'll ask
03:51the session, we have already created a session, to see if the user_id is set.
03:55And if it is then it's going to set user _id equal to that value and it's going
04:00to make logged_in = true. If it failed defined it then it will unset that value
04:04and make logged_in = false. In fact we can go ahead and say logged_in = false
04:09at the start.
04:10So now when the construction happens, it would be great if we went ahead and
04:14also just ran this method. Check the login. So start the session and then find out
04:19is the person already logged in? It works a lot like the way we did
04:22the instantiation before. We're setting these attributes based on data that we find.
04:27And then even though that's all I'm really going to do here is just establish
04:30the fact that they are logged in or not, we could have something else here that said
04:34if they are logged in then do a certain set of actions right away.
04:37If they are not logged in then do another set of actions right away.
04:41This is not where we're going take care of redirecting a user to a login page or
04:44anything like that. Don't be fooled by that. We'll take care of that somewhere else.
04:48We will do another test for are they logged in. But this is just a place where
04:51we could take additional action and I just want to highlight that to you.
04:55Now that we have a private function for checking whether they are logged in or not
04:59what we're still missing is a public way for us to find out whether the session succeeded or not.
05:05So it gets constructed, it marks all the attributes correctly, but then we need
05:10a public function. I'm calling is_ logged_in, which will check and see is
05:15the person logged in or not. This is like the bank teller being able to go to the bank vault.
05:18is_logged_in has access to this method, but we don't directly.
05:23What this keeps us from is being able to write to this method. We can read from it here,
05:27but we can't write to it. We can't set this value in any way.
05:31Only the class session can do that.
05:33Now there is two other methods that we're going to need here and those are
05:35going to be in the cases when someone logs in from a webpage. So they enter
05:39their username and password. We want to go to the database, find the user and
05:43make sure the password matches everything, and if it does then we want to
05:47say hey session, mark them as logged in now. Even though they weren't logged in
05:51when you got setup, now you need to mark them as logged in.
05:55So here's the way I'm going to do that. I'm going to write a public function
05:57called login. The database will take care of finding the user based on the
06:01username and password. If we get sent a user then take that user_id and set
06:06that equal to both the session id, so it will be stored for the future and
06:10mark it inside this object, so the object will also be updated. And then mark
06:14logged_in as true, since it was marked logged_in as false presumably before
06:18they got to that page.
06:19And that will then effectively log someone into the page. Conversely we'll want
06:24to log them out as well. So we'll need another function here, public function logout,
06:29and it will just unset that session id so that we don't remember it for
06:34the future. It will also unset the user _id here so that that's no longer in effect
06:39and marked logged_in as false again.
06:41So here now we have a session object that handles everything for us.
06:44When we fire up the application, it figures out whether they were previously logged in
06:48or not and we have the ability whether they are logged in currently to log them in
06:52and to log them out. All by just issuing these three simple method commands,
06:56logged_in, login and logout, and now our session class will take care of the rest.
07:03Now that we have written our session class let's look in the next movie at how
07:06we can write the actual login and logout pages to make use of this.
Collapse this transcript
Logging in using the Session class
00:00Now that we have a session class, let's use that class in order to login to our
00:03application. Through a lot of this I'm moving very quickly because it's things
00:07that we covered in the Essential Training. Remember you can pause the movie if
00:10you want to copy down the HTML code or anything like that at any point,
00:13or you can just use your own.
00:14The first thing I want to do is I want us to go into the public folder and
00:19I want to make a new folder inside of that folder. Actually I didn't put it in there.
00:22Let's just drag it in and I'm going to name this untitled folder admin.
00:29So that's going to be where all of my admin code is going to be put. I'm going
00:32to put all in that folder and that way it's really easy for me to try to
00:36restrict access to that folder. Index will be part of the public folder and
00:40that will be the public pages. admin will be the more private pages.
00:43The nice advantage of this is that we also have the ability to just type into
00:47our menu bar the same URL, /admin, and it will load up the adminindex.php.
00:53So let's create an index.php for admin. I'm actually going to just Option+Drag
00:57this one in there, so that I have a duplicate of it and I'm going to actually
01:00duplicate it one more time. I'm just going to Duplicate and I'm just call this one login.
01:05Now I'm going to overwrite what's in there but that gives me some files really
01:08quickly that I can work with. The index page, the page that we want to get to,
01:12is actually going to be a menu page. So I'm going to take everything that's
01:15here now and I'm going to paste over it with some new code.
01:18I'm loading in my functions, I'm loading in my session, and I actually need to
01:22go back one more directory here, dot-dot, there we go. So it goes back into the main
01:26directory then back outside of the public and then into includes from there.
01:30It's going to check and see is the session logged in or not. We wrote that method.
01:34It's a method, it's got parenthesis after it. If that's not true then
01:39redirect to login and redirect was defined inside functions.
01:43So this will make sure that we don't have access to this if we're not logged in,
01:46but if we're logged in then it will go ahead and give us some HTML.
01:50Nothing special here. It just says Menu on it.
01:52Notice here at the bottom for the copyright, I'm using that date function that
01:56we learned back in Chapter 2. We talked about string for time and we talked
01:59about date. I'm using date just to display the year of the current time.
02:02So the copyright will always stay current. It's a nice trick so that my site doesn't
02:06fall out of date. When it goes from December 31st to January 1st my website
02:10will automatically update to say the following year.
02:13So I'll save and I'll close it. That will be enough to get us going on that page.
02:16Now what we really want to focus on though is this login page. So we have
02:20everything we had before. We have to change our directory structure slightly,
02:23so that we look backwards one more directory and we'll talk about how
02:26we can improve that coming up soon.
02:28We also need to add a new one here, which is going to be for our session file.
02:33Session and that will load up the session for us. We're not going to want to do
02:37any of these steps we were performing before. We just want to get everything loaded up.
02:40Now it's a good policy that if of course the person is already logged in,
02:44let's go ahead and just forward them onto that index page, that menu. No reason to
02:47waste any time on this page. Then we're going to want to have our form.
02:51Remember to give your form tag a name attribute so that we can check and see it
02:55when it's submitted. That's how it will have a single page submission.
02:58We talked about that previously.
03:01We want to clean our data that comes in from the form. I'm just going to put trim on it.
03:04And then we just going to do this step here, Check the database to see
03:07if the username and password exist. That's going to be a placeholder for now.
03:10We are come back to that in a bit. But for now we're going keep going with
03:13the rest of us our form and we're going to say well, if the user was found then tell
03:19session to log them in. So this has got to come up with found_user,
03:23found_user, and there will be some test performed to see whether or
03:27not the user is found.
03:28If they are, log them in and once they are logged in redirect them to that menu page.
03:33If not then we're going just display a message that's says
03:35the combination is incorrect, and if the form hasn't even been submitted,
03:39then we're just going to initialize those values.
03:42Now you can probably guess what the form below that is going to look like.
03:45I'm just going to paste it all in there and then come back and look at it.
03:49It's just HTML, the header, everything's pretty much the same, staff login.
03:53We're running that output_message, which is in our function, just to make a nice
03:56pretty output of our message. The login form loading the same form again,
04:00login.php. username, the value for it is going to have htmlentities applied
04:05that escapes any values that might be dangerous.
04:08We want to make sure we always do that on user-submitted data and
04:11the password and then we'll submit those, and then same thing. Copyright at the bottom
04:15and the last step is if the database connection is there then we can
04:18close it. So that's a simple form that we're going to be using for that.
04:21So now we need to just find out the answer to this: how do we determine if the
04:25username and password exist? Well, we could certainly do the checking here,
04:29but again we're doing object oriented. We want to put that into our object.
04:32We want to ask user can you check for me and see whether or not this username and
04:37password is authenticated. So I'll say authenticate username and password.
04:44So that's the key step here is that we're going to say hey model, run your
04:48static method authenticate using username and password and give me back a found_user.
04:52If we get false back then we know that they weren't found. But if
04:56we do get something back and it comes back true then, then we're going to login
05:01the user or not.
05:02So we'll save that. Now we need to write this authenticate method.
05:05So we'll just push this aside and we'll open back up user again. I'll go ahead and
05:09collapse down these functions that we were working on before and now right
05:13before full_name, let's do public static function authenticate. And of course
05:20it's going to be passing in the username, give it a default value, and
05:26password, which we'll also give a default value.
05:30So there is our placeholder for it. Now what we need to do is make it actually
05:34find the values that we want. We haven't taken care of escaping those values
05:39yet for SQL. This is a good place to do that. So we'll bring in the database
05:45from the global scope. We'll make sure that those values are okay to use.
05:49Then once they are okay, the SQL we're going paste in is going to check in the
05:52user table and see if the username and password, if that combination, exists.
05:57Now we're not doing any encrypting on the password. We talked about that in the
06:00Essential Training. I don't want to complicate it here. So it's just a plain
06:03text password. You know how to do encryption if you need to do it. And limit 1.
06:07Now the find that we want to perform though is just like this find_by_id.
06:12If we go up here, I'm actually going to steal all this code and drop down here and
06:18paste it in, but instead of find by that old SQL, we just want to change it to
06:23be our new SQL.
06:24So find_by_sql, it will give us a result. It should be a single person or false.
06:29If it's a single person, it will do the array shift on it. Otherwise,
06:32it will return false. So we'll just save that. Take a look for a second and make sure
06:37that you understand what it's doing. It's basically saying hey,
06:40can you find this person? Authenticate are they in the database.
06:43It's not actually doing anything to the session. We could, we could certainly
06:47do that here, but we're not. We're just saying find out if they are there or not.
06:52Then over in login, if there they are, then we tell the session to mark them logged in.
06:57So we're handling it here on the page. Yes, they are there.
07:00Maybe we want to do some additional checking, maybe we want to say well, let's make sure
07:03that the found_user has paid all of their dues or something. Let's make sure
07:07they are up to date. We may want to examine that object further before
07:11we actually log them in.
07:13So we'll do index.php to get them all logged in. Now that we have done all this,
07:18let's try it. We may very well have some bugs in it. So let's open up Firefox.
07:23Now instead of just public we want actually go to admin.index.php.
07:28So here is the Photo Gallery. Now I'm noticing that I'm not getting my CSS.
07:33That's one bug. So let's just take a quick look here. I was asking for style sheets.
07:38I have got to go backwards one directory to get the style sheet for that.
07:41Let's see if that comes up now. There it is. So there is my style sheet.
07:46Let's go to Menu and do the same thing while we're at it, because I know
07:49it's going to have the same problem.
07:50So that index.php, we're also going to need to tell it to look backwards one directory
07:55to get to the style sheets, okay. So now we have got that done,
07:59let's try logging in. I've got KSkoglund and secretpwd was my password and now
08:07I'm logged in and there it is. It's not very pretty because the menu has actually
08:10got a flaw in the HTML. Let's take a look that real quick and fix that.
08:15It looks like I'm missing a close div tag. There it is. Close that div tag.
08:20Now let's come back over and try and reload that page and there we are.
08:22So now we can go straight to the index page. We don't have a logout action.
08:26We haven't written that. So we would need to do that if we want to test logging in
08:29and logging out. But we did successfully see that the first time we try to go to this page,
08:33it redirected us to the login. Then we once entered our password,
08:36the session object took care of it and then let us proceed to the menu page.
08:39We have now successfully been able to use it to login.
08:42Now you will notice that in these files I had some problems here with
08:45the styles sheets being located in one place and having to change directories
08:49here again. There is a way that we can do this more efficiently and handle it better
08:54and I want to look it that in the next movie.
Collapse this transcript
Initializing files and path constants
00:00In this movie I'm going to show you how it can be beneficial to have an
00:02initialized file that takes care of loading in a lot of other files, and also
00:06have to establish the path constants that will help you out.
00:09In the last movie we saw we had to make some alternations to this require
00:12ones to put another ../ in it as soon as we created this admin directory over here.
00:17And we even had problems with the stylesheets and locating the right
00:20stylesheet as well.
00:21We have kind of been laboring a little more than we needed to over finding some
00:26of these files and so I want to try and clean that up a little bit.
00:29It also should set out some alarm bells in your head that we're repeating
00:32ourself so many times by requiring these same files over and over. What it would
00:37be better to just have one file that would initialize everything for us and
00:40that's what we're going to do.
00:42I am going to create a new file here and I'll save it in the includes folder
00:46and we'll just call it initialize.php. And I'll put my PHP tags in it to start with.
00:53Let's take all of this here at the top and we'll just copy it. Move it
00:58into initialize and hit Paste. Back over here that means I can reduce all of this down
01:04to just initialize. And at the top of every one of my pages
01:09all I have to do is say initialize and once it does that, it will load up everything
01:13that it needs to load up.
01:14So already we have made it better and if we decide that we need to take out one
01:17of our classes or add in a new class, it will certainly instantly become
01:21available to all of those pages if they need it.
01:23Now you may be thinking well I don't necessarily need all of those classes
01:26every time. So am I losing something in efficiency by loading them all in?
01:30You are losing a little bit, but PHP is very fast with loading in these classes and
01:34everything. That doesn't take very long. It takes a lot longer to do things
01:37like go to the database.
01:39So speed is not going to be as much as of concern for us, as code organization
01:42and we can break it up and modularize it a little more if we find that speed
01:46becomes a problem. We still have this .. here. We can take that out because now
01:50this is actually in the same folder right?
01:52So we'll go through each one of these database and user and we actually had one
01:57more earlier if you all remember which was config and so we'll go ahead and
02:01load that in at the same time. Database was loading because it needed it, but I
02:05might as well go ahead and load in the config file here.
02:08Now what I want to do is come up with some definitions for some paths that
02:11we can use that will help us to locate files easily and see how that will help us.
02:16I'm going to start out by defining the core paths.
02:19The first thing I'm going to define is a constant for DS and if it's already
02:22defined then I'll make it null. But otherwise I'm going define it as the
02:26Directory_Separator. That's a special PHP pre-defined constant. If you are on Windows,
02:31it will be a backslash. If you are on Unix, it will be a forward slash.
02:34But PHP takes care of figuring out which one it ought to be when it boots up.
02:38So that will make sure that any path that we write we're able to use DS and it
02:42will work regardless of what file system we're using.
02:45The second one I wanted to set up is Site_Root. Let me just make this a little
02:49wider, there we are. So if the Site_ Root hasn't already been defined, then
02:52I'm going to define it and I'm going to define it as being the Directory_Separator
02:56and then 'Users'.DS.'Kevin' so on 'Sites' 'photo_gallery'. The path to
03:01my application basically. Yours will be definitely different from mine.
03:04So you will want to work that out, so it's the same as yours.
03:06If you are on a Mac or on Unix you can go into the Command line and you can try
03:11and navigate to that place to where your site is let's say photo_gallery and
03:15then it shows up there but you can also do pwd and that will show you the list.
03:19That will work on Unix. You also can navigate there. You can go into the hard
03:23drive into Users into Kevin and so on till you get to the path.
03:27So we're talking about an absolute file system path that's important, it's the
03:31file system not the web server path but the file system path. This is for PHP
03:37to locate the files that it needs. So now for example I could tell it in order
03:41to find those includes files, no matter where the file is that's asking for it,
03:45the way to get there is to go into the Site_Root and then into includes.
03:50In fact I'm going to be referencing those include file so often, I'm going to go ahead
03:54and make a path for that as well.
03:56So Lib_Path is going to be path to the Library, that's what the Lib is from and
04:01I'm going to say if the Site_Root and then the Directory_Separator and includes
04:04and that's how we can find that. And then we can make use of that.
04:07Let's say Lib_Path and the Directory_ Separator again and config, function,
04:13session, database and user. In fact I'm going to go ahead and just paste in
04:17some comments that I had prepared for these, that I'm going to load in the
04:21config file first and that's to just get all those configurations setup. Then
04:25I'm going to load in the basic functions, so that everything after that can use
04:28them. Then the session, and the database, those core objects and then any of my
04:32database related classes, those will come last.
04:35The order is important and if I do need to change the order I can just do it in
04:39this file. Now notice that I can't defined these in the config file if I want
04:44to also be able to use Lib_Path here. It won't have it defined unless we have
04:48done this step up here. So just take note of that.
04:51The second thing I want to point out to you is that back over here in the login
04:55file we can't use it here either because when this page first loads, it has to
05:00know how to get that initialize.php. Once it's gets there then everything gets
05:04defined and it taken care of, but we don't have those convenience helpers for us
05:09at this point.
05:10So where does it help us then? Let's go into database.php. Here we can use that
05:16Lib_Path.DS and then I'll make sure that it can always find the config file,
05:22I'll just copy and paste that. And let's go into functions. We have autoload;
05:27we were looking for the function earlier. Well here is how we could find it.
05:30We can go to the Lib_Path and then look for the class name there. That's helpful.
05:36Let's also look in user.php and require_once database can do the same thing,
05:41the Lib_Path and the database.
05:43So we now have a common way that we can always find the library. Once we have
05:47run that initialized file, we have those paths established for us. So that
05:52makes the top of the file a lot cleaner, but what about the stylesheets and
05:55everything? For that we're going to need to establish headers and footers
05:58layouts like we did in the Essential Training and we do that in the next movie.
Collapse this transcript
Using path content for layout
00:00In this movie, I want to take the path constants that we created in the last
00:03movie and use them to help us with the layout of our site. Specifically,
00:07the headers and footers that will go at the top of every page. We broke those out
00:10in the essential training and we're going to do that again here.
00:13Now, I have already created a folder called layouts. So you want to create this
00:17inside your public folder and I have put four files in it header, footer,
00:21admin_header and admin_footer. Now, I'm going to show you just the difference
00:25between header and admin_header. Let's open both those up. You see that really
00:30the only difference between them is this dot-dot in front of the stylesheets and
00:34we ran into problems with that earlier.
00:35So, the admin_header is going to find the Style Sheets by going back one
00:39directory from the admin folder. That's how it's going to make sure that it finds it.
00:42Now, you may be wondering, why we don't just use Site Root here at
00:46the beginning? And that's because it won't work for us. Site Root is so that
00:49PHP can locate the other PHP files that it needs to put things together for us.
00:54This is different. This is the file that's going to be served up to the web
00:57browser and this is the HTML.
01:00So, it's going to be the Site Root, so this is relative to the site. So in this case,
01:05if we open up Firefox, we're inside the admin directory. We need to go
01:10back a directory to the public directory. Now, it doesn't matter where this
01:15photo gallery exists as long as the web server serves it up. We could be in
01:19a number of different places. This will be www.abc.com/photo_gallery or maybe
01:24even just abc.com/public. The point is that it's a relative route in the URL
01:30and that's how we're finding it, not a absolute file path.
01:33So make sure you understand the difference between the URL route that
01:36we're working with and the file path that we're working with. I'm going to make one
01:40more change here, I'm just going to say Admin at the top of this so that's nice
01:44and clear that we're working with the admin area and I'll save both of those
01:48and the footers are exactly the same between the two, there is no difference
01:51and I'll just open it up so you can see it, it's just the bit of HTML that was
01:55at the bottom of the file before.
01:57I am going to open up index.php which is the menu file and I'm going to go
02:02ahead and start by making this also be our initialize.php, I want to take
02:08advantage of that and then all of this here is now going to be replaced by the
02:14template and all of this here also will be replaced by a layout template.
02:19Now, we could just simply put in some PHP and do in include, remember include.
02:24Include will just include that HTML file, drop it in right here and then all
02:28we have to do here at the end just put in what we wanted to include to that path,
02:32admin_header.php. But since, we're going to be doing this a lot and
02:38that's a cumbersome thing to write each time. Instead, I'm going to make a helper that
02:42will help us to do that.
02:43So I'm going to copy it and we'll go over to functions and we'll put in a
02:48helper method here, function and let's call it include_layout_template and
02:56we're going to provide it a template name with default of nothing and then
03:01we'll paste that in, the include statement that we're working on, and instead of
03:04telling it which one it's going to be just whatever template is sent in.
03:09So, now, we can just use this include_ layout_template helper and when we call
03:14that function and this is just a root function it's not part of a class.
03:18Then we'll able to output that template that will just make it nice and easy to
03:21write, so let's try that. There we go include_layout_template, admin_helper.php
03:29and we can do the same thing for the footer, include admin template,
03:34admin_footer.php and that will take care of our header and our footer and
03:39we can really focus on what's in the middle now.
03:43Now, we could put this into a class of its own if we had a lot of these kinds
03:47of helpers for layouts, we could roll them into a class for easy access, but
03:52right now since there is just one, I'm going to put it in my functions file and
03:55later, I can roll it into a class if it becomes more complex. So let's save
03:59this and let's just try all this out and make sure that it's all working for
04:02us. We're going to Firefox and see I've got this weird space up here at the
04:06top? I'm just going to open up my CSS real quick. I think this right here on
04:11header h1, if I could just put in a margin of zero on that h1 tag, close that
04:18up and reload it there it goes, now it disappears.
04:20So, I'll leave it here to apply these templates to the other pages that we have
04:24been working on. The important part I want you to see here is that we were able
04:27to use Site Root to tell it where to locate those files. Site_Root inside
04:31public, inside layouts, locate the template and we can make use of Site Root in
04:36that way anytime we need PHP to be able to locate a file and it doesn't matter
04:40where it's located, it doesn't matter that if it's inside the public folder or
04:44if it's inside admin, we'll still be able to locate the layouts folder and
04:48these files from wherever we are.
Collapse this transcript
Late static binding
00:00In this movie, I want us to understand what late static bindings are. Before
00:04I really try and explain what they are, I think it's best if I first demonstrate
00:08what problem they solve.
00:09Let's open up our User class that we created earlier. Notice how our User class
00:13has methods that make database calls like find_all and find_by_id.
00:18So far we haven't been working with any other database tables but we will be soon.
00:21For example, we'll have a table that will store the information about
00:24our photographs and our comments and when we do, we'll most likely want to have
00:28similar methods in their classes that will also find all photographs or find a
00:32comment given its id. And you may even recognize a lot of these common
00:36behaviors working with databases from the Essential Training, where I refer to
00:40them as CRUD. That's C-R-U-D, which stands for Create, Read, Update and Delete
00:45and that's pretty much the standard interactions that we have with our databases.
00:49Well, since we have learned about class inheritance, we know a good programming
00:53habits tells us that we should put all of these common methods in a common class
00:57and then inherit those methods into our subclasses. So find_all will be
01:02made generic enough that it can be reused over and over by different classes.
01:07Let's start that process together. Let's have our User object extend from
01:12a new object called DatabaseObject. So, I'll just come up here to the top of my class
01:16and I'll say extends DatabaseObject. Now we need to create that class,
01:23I'll save this for now and I'll open up a new window in TextMate and let's go ahead
01:28and just save that and I'm inside the right place and I'm just going to call it
01:33database_object.php. And if we take a look at user.php, we can go ahead and see
01:42that all of this is actually going to be the same. We're going to go ahead and
01:44require the database. We're going to need that. The class name now is going to
01:48be DatabaseObject, and we'll go ahead and just close the class for now.
01:53So now our User class will inherit from this empty class. It won't really do
01:57much for us but the inheritance does exist and we could have other classes that
02:01inherit from DatabaseObject. So now DatabaseObject is ready for us to put
02:06methods into it that will be reused by these subclasses.
02:10The one last step that we need to make sure we do is also to go into
02:12initialize.php and make sure that we load that up. So I'm just going to copy
02:17this line here and also load up database_ object, so that will get required as well.
02:22We can make sure that we have that as a core object ready to us before
02:26we start loading in classes like user.php.
02:30So just to prove ourselves that this all works, let's go ahead and bring up Firefox.
02:33I'm here at my photo_gallery/public page, this index.php, and you can
02:39see that it goes ahead and just brings up that same information before,
02:41where it's finding a user in the database and then displaying the information about that user.
02:46We will come back to this page periodically to check our work. For now,
02:49I'm going to hide that and let's just go back to user and take a look at these
02:53methods that we want to move. Well, we do want to move find_all, find_by_id,
02:58find_by_sql but authenticate and full_name are really unique to user.
03:03That's not something that will be reused but instantiate and has_attribute will be reused.
03:08So let's just take full_name and I'm just going to move it up here to the top
03:13and I'll fold it back up again, so it's out of the way and same thing with
03:17authenticate. I'm just going to grab all of authenticate and move it up here
03:22out of the way and I'm going to go ahead just to make it really clear,
03:27I'll put here at the top of these that these are the Common Database Methods, okay.
03:37So now everything that's above this comment is unique but everything that's
03:42below it is not. So let's take a look inside each of these. find_all,
03:45you'll notice that the problem is that it's looking for users. So we need to also have
03:50a way of specifying which table will be used for each model. We know how to do that.
03:54We can just put another variable here at the top. It's going to need to
03:57be static, so that we have access to it in our static method and we'll just
04:01call it table_name and we know that's going to default to users.
04:08So, I'll also while I'm at it go ahead and say that it is protected.
04:12Don't have to do that, but that's a good access control thing to do and then
04:15I'll take this out and now we can ask for self::$table_name. And we can do that
04:25again everywhere where we find users. Here it is again. Now, I can't use this
04:30notation. That won't work with self. Instead, each time I have to actually
04:34break out of the double quotes and join it in there. So I have just done it
04:39again here. So select all FROM and make sure there is a space here.
04:43The space is important. And then after the space, self::$table_name and then another space after it.
04:50Let's check find_by_sql. It does not make any reference to the table_name and
04:56instantiate, it does not make any reference to the table_name and
04:59has_attribute, does not. So now we have made these reusable.
05:03Let's just make sure that it still works. We just want to make sure we didn't break anything
05:06in that process, so I'll save it and we'll just come back over here to our main
05:11Photo Gallery page, load it up and everything is still load just fine
05:14when I reload the page.
05:18Now I want you to stop following me for a second. I'm going to do a bit more
05:21but I don't want you to follow on because what I'm going to demonstrate next
05:24will not work and I don't want you to get tangled up. So just sit back for a second
05:28and watch me demonstrate the rest of this. I'm going to take all of
05:31these Common Database Methods, I'm going to cut them, I'll save that user
05:36object, I'll come into my database_object and I'll paste them in here.
05:41So now I'll just fold them back up again so they are out of the way. Now all
05:47those methods are in the database object and they should be inherited by user.
05:52So everything should still work. Those methods should just come down into user
05:56and be available for me to use. Let's try it out though. I'll go into the Photo
06:00Gallery and reload. Oops! It says well you need the table_name.
06:03That was an oversight of my part. I need to make sure that I still go ahead and say
06:07protected static $table_name because it wants to find that table_name still.
06:15Let's come back and try again, oops! Database query failed. It was trying to do
06:19the find_by_id but it came up with bad SQL and the reason why it came up with
06:23bad SQL is because self::$table_name was nothing and so it tried to just select
06:29all from blank. So it created a problem. We got an SQL error.
06:33Now this is a symptom of the problem I'm trying to show you, but just to keep going.
06:37Let's say we went ahead and set the table_name="users". Now I know that's not
06:41reusable but it will allow us to hopefully avoid that error.
06:44Now it should have a table name.
06:45So we'll save it, we'll come back and reload it. Now it comes back and says
06:49oh, wait a minute, you don't have the method full_name. And you may think well,
06:54that's because we didn't move full_name, we didn't promote it and that's the problem.
06:58Well, it is, but that's a little bit deceptive. The real problem is
07:02that it's asking for full_name on the DatabaseObject class, notice that.
07:07That class ought to be user. That's what we're working with. We're working with our
07:11inherited child object. We should be inheriting things from DatabaseObject but
07:16we shouldn't actually be working with DatabaseObject directly. We shouldn't be
07:21calling its method; we should be calling user's methods.
07:24So somehow when we asked for it to find the user and instantiate a user object,
07:29instead it returned and instance of the parent object. If we take a look at
07:33instantiate we'll see where this is happening. It's because we have object, new self.
07:39So it's returning an instance of itself. Now we would expect that would
07:44return the user object, but it doesn't. And we can go ahead, if we were to put
07:48in User here, then it would solve the problem. It's just not reusable at that point.
07:52What we really want to be able to say to make it reusable is, well,
07:55whatever class has inherited this, create a new instance of that. So that's where
08:00our problem is and in fact, that's the problem we're having up here with
08:03table_name was then when it was asking for self::$table_name, it was also
08:08looking in the DatabaseObject class to get its table_name, not in the users class
08:13which had a table_name.
08:15So the problem in both cases is this word 'self.' Anytime we use self in a
08:19static method, it refers to the actual object where it resides, not the class
08:24inheriting it. To put it in another way, when PHP loads up the DatabaseObject class,
08:29it binds, B-I-N-D-S, it binds every occurrence of the word self to class.
08:35Before the user class has even been defined. The binding happens early,
08:39when it's created, not late when the object is called or what we can also refer
08:44to as at runtime.
08:46Now, as the contrast and to make this point really clear, $this always refers to
08:51the current instance. It doesn't have the same problem that self does. But self
08:55we don't have an instance. We're in a static method, we're in a class method.
08:59So self is always going to have this problem. Now, you won't hear the phrase much,
09:03but this could be called Early Static Bindings and as you can see it presents
09:08some headaches that are really hard for us to work around.
09:10Now there are a couple of different workarounds that we could try. The first is,
09:13we could try to simply avoid using static methods at all. We would just use
09:18instance methods instead. We saw that earlier, how instead of calling a static method
09:22we would instead define it as a regular instance method and then just
09:26create a new instance and then call the instance method on it. This is a very
09:30valid approach and one that a lot of developers to adopt. I think it's a shame
09:34though not be able to use static methods as they were intended.
09:37Now the second workaround is to try and deduce the class name and we saw
09:41earlier how we could use get_class on an instance to figure out its class name.
09:45Unfortunately, if we do that in this case it's still going to return
09:47DatabaseObject. Now there are a lot of different work arounds on the php.net
09:52website where developers have jumped through hoops to be able to figure out
09:56what this class name is. I don't recommend them and I'm not going to show them
10:00to you, but there are some there if you want to try them. And then the third
10:03and I think best approach is late static bindings. So we're finally back to
10:08where we started at the beginning to talk about late static bindings.
10:11Late static bindings is a feature of PHP 5.3. Now as I'm recording this,
10:16that's not out yet. It's in alpha, so it's still being tested but while you're watching it,
10:20you may already have installed 5.3, in which case you will have these features.
10:24Instead of get_class with late static bindings we also have
10:29get_called_class, so that we can find out what class actually called this
10:34static method. So that's going to allow us to figure out what the class name is
10:38and create a new instance of that class. The other thing that we can do is
10:42simply say static:: as our scope resolution operator instead of the self scope
10:49resolution operator.
10:50So instead of self, everywhere that we're using that in our static methods
10:53we can just use this new keyword, which is static, and again that's only in 5.3 that
10:58we have that available and this is different than putting static in front of
11:02our function name. This is using it as a scope resolution operator to say
11:07I want you to make a late static binding, a binding that happens at runtime,
11:12not back when you were defined at the very beginning.
11:15So just to be clear once you are using PHP 5, you will be able to move all that
11:19code into DatabaseObject and everywhere you have self, you will simply be able
11:25to call static. And if you ever need to get the class name, you can do that by
11:30simply saying class_name = get_called_ class and should return the class name
11:38to you. And then we can create a new instance by simply telling it to create a
11:42new instance of the class_name.
11:45Now if you don't have PHP 5.3, which is the case for me, you are going to take
11:51all of that code and you are just going to replace it with a simple comment
11:54that says I'm waiting for Late Static Bindings in PHP 5.3. Now we're all set.
12:05We're ready to go with that. I'll go ahead and put my methods back in here for now.
12:13And we have placeholder inheritance in place so that all of these Common
12:17Database Methods can just be moved over here and we'll know how to do it once
12:21we have PHP 5.3.
12:23So if you have it and you want to go ahead and attempt it, go for it. Now,
12:27the details may have changed a little bit after it finally gets released, but
12:30at the moment the best place to find out information about it is going to be at
12:34php.net/lsb. So Late Static Bindings. http://www.php.net/lsb. So you can look up
12:42more information there, find out all the details and if it changes,
12:45that's where also some of those implementations changes will also show up as well.
12:49The important thing for us now is that you understand what the issue is and
12:53understand why it won't work without late static bindings. Now we're ready to
12:58move on the next chapter where we can talk about working with files and
13:01directories so that we can start to upload photographs.
Collapse this transcript
7. Working with Files and Directories
File system basics
00:00In this chapter, we're going to focus on working with files and directories in
00:04PHP. I want you to just set everything we have been doing with object oriented
00:07programming aside. We're going to be focusing on the file system for now and
00:11we're going to be coming back to the object oriented later when we talk about
00:14uploading files to the file system.
00:16But first we have some basics that we need to take care of and because
00:19we're going to be setting all of that object oriented programming aside, let's close up
00:23our photo_gallery and let's go back to the btb_sandbox where we were working earlier.
00:27And let's create ourselves a new file in there. Let's call it
00:31file_basics.php. Make sure you put it in your btb_sandbox and this will be the file
00:37where we can take a look at some of the basics of working with files.
00:40Now, the most important thing of working with files in the file system in PHP
00:45is the magic constant file, __FILE__, I'll go ahead and put a br tag at the end
00:54of this. Let's go ahead and save this file and let's open up a new browser window.
00:59Again, we want to make sure that we go back to our sandbox and load up
01:03file_basics.php, and look what it gave me. When it echoed back the value of
01:09that magic constant file, it gave me the full path to get to that file. So
01:15it illustrates that it knows exactly where that file is located. The file that
01:18we're loading up. So __FILE is this file that's being loaded.
01:25Now, there is another magic constant that goes along with it which is LINE.
01:31Let's load that up, and you will see it comes back and it says 4. Now that it's
01:34become obvious then that line tells you what line we're looking at. We can see
01:37here it's numbered 4. One caveat with this is be careful once you include files
01:44because then the line number may not be what you expect. If we have other files
01:49that we included, if we're calling functions inside of functions, so just be
01:52careful about that with line number and then be aware that it may not be quite
01:56what you expect.
01:57Now if you want to get the directory information about the file that we're working in,
02:01we can do that by calling a function on it, dirname(__FILE__).
02:06We'll pass that in and it will be able to simply parse out the directory name
02:12from the file name. I want to also at the same time show you that there is
02:17another version of this, which is only in PHP 5.3, and that's simply say DIR
02:24and that's the same thing as a magic constant that will return the directory name.
02:28Now you will see mine is a different color because I'm not running 5.3,
02:31yet it hasn't been released at the time that I'm recording it. This does the exact
02:35same thing. They are equivalent. So for now you can use this. In the future,
02:38you can use this, but you also can take advantage of this once you are using 5.3.
02:43So let's just bring those up and try them, you see it didn't work for me. If
02:46you are running on 5.3 you probably will see the same information there a second time.
02:50So now that we understand how to reference the file that we're in, and the
02:54directory in we're ready to start taking a look at a few functions. The first
02:57of these is simply file_exists. Does the file exist? And if it does, return yes
03:03or no. I'm just using a simple ternary operator here to return yes or no. Of
03:07course, the file that we're in does exist. That's not very interesting,
03:12but we could also say something more interesting like the directory name of this file,
03:17when added to /basic.html, does that exist?
03:22Now, notice we're building up a path here. We found a directory name and then
03:25from there we added basic.html. So here is the directory name btb_sandbox.
03:30It's just a string and to that we'll put /basic.html. Does that exist?
03:38Yes, both of them exist, the file that we're in and basic.html.
03:42Now, the quirky thing about file_ exists is that it also works on just
03:47directories. Does the directory exist? Is the same thing as file exist. So
03:53don't be confused because this is file, but it really mean is this part of the
03:56file system does it exist. So if we try that on the directory name it also
04:01returns true. It does exist.
04:03Instead, if we want to find out something actually is a file or not, we need to
04:07call a different method which is is_ file. So we can call that both on the
04:11basic.html page and on the directory, and we'll see what we get back, yes and
04:17no, and of course, the corollary to that is being able to ask not just is it a
04:21file, but is it a directory, is_dir. So is this a directory? Well no, it's not.
04:28But this should be a directory.
04:29So we'll just do both of those and check sure enough no and yes, so the answers
04:33that come back. And just for the sake of completeness I want to show you that
04:36you also can simply reference the directory that this file is in by calling
04:41dot, dot. Remember, how to use dot, dot when we were navigating the file system
04:45from the command line, it works here as well. So is dot, dot (..) a directory?
04:50And it figures out, yes that's what we're talking about. It is the directory
04:54that this file is in. So that also works as well.
04:57Now, these are going to make up the fundamental building blocks for working
05:01with the file system because before we write a file, for example, we want to
05:04check and make sure that the file doesn't already exist. Well, after we have
05:08written a file we want to make sure that it does exists. We might want to check
05:12that the file exist before we try and read it, or make sure that it is a file
05:15and not a directory, before we try and read it.
05:17So these are going to be the toolbox that we're going to be using going
05:20forward. So get use to them, experiment with them a little bit,
05:23and when you are ready, move on to the next movie where we'll take a look at file permissions.
Collapse this transcript
Understanding file permissions
00:00In this movie, I want to just start to understand file permissions, or more
00:03specifically who has what permission to access, read and write our files and
00:10directories. Now permissions can be a very thorny issue and it require a lot of
00:13tinkering to get things exactly right. It's a big enough subject that
00:16I actually recommend that you go off and research it further on your own.
00:19But I'll at least give you an introduction to get you started on the right path.
00:22Now one of the reasons why we want to use file permissions is because of the
00:26security that they provide. They give an extra layer of security that ensures
00:30that people on the web cannot access files and folders that we don't want them
00:34to and once we put our website into production, put it out for the public to
00:38use, we want to be constantly vigilant about exposing our website to hacking.
00:43One tip that I'll give you is that it's always a good idea if you are going to
00:46have files be uploaded that you upload them into their own special separate
00:50directory. Separate from the rest of your code, because then we can make the
00:53permissions on that folder looser and we can say you are allowed to write to
00:57this directory, but some of our other directories can be a little bit tighter
01:01in their security. We can say no you aren't allow to write anything to these
01:05directories, and that way we can make sure that people don't change our files
01:07or modify our code.
01:09In general, you want to grant as few permissions as it takes to get the job
01:12done. Now that's once we're in production, once we have launched to the public.
01:16For now we're in development, we're on our own machine and we don't need to
01:18worry about hacking. So we can have our permissions be wide open, but it's
01:24still going to be important for us to understand file permissions to make sure
01:27that we're allowed to do the things that we want to be able to do on our
01:29developed machine, that permissions don't get in our way and that's all we're looking at now.
01:33Now, most of the way PHP is going to handle permission is going to be the way
01:37that Unix handles them, so I need to say a word first about Windows and how
01:41Windows File Permissions works. It's a little bit easier and it's a little bit
01:44harder. The reason it's easier because it's going to simply manage through the
01:47Properties/Security tab. So you will go to the Properties Profile, click on the
01:52Security tab and then you can manage the permissions for that file.
01:55If you can't see the Security tab you may not need to enable that feature first. Now,
01:59the default permissions that Windows has may work in general, it tends to be
02:02wide open and so you probably won't run into any problems.
02:06The other reason it's easier because the Security model for Windows is much
02:10simpler. You basically are user who either has access or doesn't have access.
02:14Now, it's a little bit harder though because different versions of Windows
02:17handle it slightly differently, in the way that the Properties and the Security
02:20tab work are little bit different.
02:22In this chapter we'll also present a little bit of a problem for you,
02:25if you're a Windows user because many of the PHP methods that we're going to be talking about
02:28are either going to be fully ignored or partially ignored. So Windows
02:33users default permissions may work and you may not need this chapter at all.
02:36But I think it is still useful for you to understand in case you deploy to
02:40a different environment later. PHP, remember, is not a platform specific.
02:44So now let's talk about the way that MAC OS X, Unix and Linux do there file
02:49permissions because they are all done the same way. Basically, we have three
02:52categories of users that could be coming to our file. We have user, which is us,
02:58the person who created the file, the owner of the file. There is a group,
03:02which is a group of users, and we can assign people to groups and then there is
03:07other, which is everybody, the public at large. So it's not us,
03:11it's not someone in one of our trusted groups, it's just other.
03:15And we have three types of actions that we can do to a file, or even to our folder,
03:20and that is to read it, to write to it or execute it. And in case of
03:24folders or directories execute actually means list the contents of what's in
03:28the directory. But since we're mostly interested in files, we're talking about
03:31being able to run executable files.
03:34So let's impose that we have an imaginary file, and we want to grant
03:37permissions to user group and other that look something like this. We want our
03:41user to be able to read, write and execute a file. Group can read and write it,
03:45but not execute it and other can read it but not write it. It's just a real
03:49simple example meant to show you how we can have different permissions for the
03:53different categories.
03:54You will notice that I have those abbreviations r, w and x next to read, write
03:57and execute. That's because those are the abbreviations we use
04:02when we summarize these listings. So for user, if we can both read, write and execute,
04:08it gets r, w and x, and in group you will see it gets r and w and then just a
04:12minus sign in place of the execute. Other, the same thing but with only the r
04:16and then two dashes. We call this symbolic notation, and you will see it from
04:21the command line inside Unix, Linux or MAC OS X. Usually they are all run
04:27together and they are in that same order user, group and other.
04:30Now, there is another kind of notation that you need to know about which is
04:33called octal notation. Now, in order to get from octal notation to symbolic
04:37notation, you are going to need to do a conversion, and the key for conversion
04:40is what I have got there. r = 4, w = 2, x = 1 and the - = 0. So then with that
04:48key in mind, we can take rwx and convert it to 7. And rw will just be r+w so
04:57that would be 4+2=6 and r by itself would be 4.
05:01Now, we have a shorthand for being able to talk about that whole string of
05:05letters up at the top, and that's called octal notation. So 7, 6, and 4
05:11represents the exact same thing as the symbolic notation rwxrw-r--. So 764 is a
05:18lot easier. Once you do a lot of these file permissions you start to get
05:21familiar with them 777 means let everyone have access. 000 means let no one
05:27have access, 666 means let everyone read and write it but not execute it. So
05:33you start to get the idea.
05:34So before you move on to actually demonstrate this from the command line, I
05:38want to talk about one more concept, which is who am I. Now, that sounds very
05:42metaphysical, what I actually mean is who is the web server. We saw from the
05:46file permissions that there is an owner of these file, so we have to know who
05:50the owner of the file is and then know who the web server is to know whether
05:54the web server has access or not.
05:56Now, often you will find that the answer to who am I is nobody. That's sound
06:01like a Zen answer but in fact that is a valid user on a lot of Linux systems is
06:06nobody. Sometimes though, instead it will be WWW or Apache, and I'll show a way
06:11that it might help you to determine which one of these your web server is running as.
06:15So here I'm at the command line, and I'm already navigated inside my
06:19btb_sandbox folder so that we can look at the files that are there. Now the
06:24first thing I want to show you is that if we type ls, it will give us a listing
06:27of all our files if we type ls - la, it will give us a listing of all our files
06:33with their permission information. So you will see now in this list these
06:37symbolic notation that we were just talking about. So for example, in
06:41parents.php we have read and write permission but not execute for the owner of
06:46the file, and then we have the group set to be able to read it and everyone can
06:51read it as well.
06:53Now, we also can find out who the owner of that file is. That's given right
06:57here. That's the first column where it says kevin. So I'm the owner of the file
07:01here is well obviously say something different. And the group information is
07:04the second column there, what group owns this file, what group has access to it.
07:09Now, we're not going to be talking a lot about groups but the concept is very
07:12simple. If we were to take users and put them into a group we could then assign
07:16ownership of a file to a group and then everyone who is in that group would
07:21have those access permissions. For now we're just going to be working with user
07:24and focusing on the user having access.
07:27So we asked who am I earlier. My web server is most certainly not kevin. Now it
07:32might be the part of the staff group but I don't think it is. So the question
07:35is what access then does my web server have to parent.php. It's not the user,
07:40it's not the group, so it would be other. So in this case it would have read
07:44access. If we wanted to modify those permissions, which we'll see how to do in
07:47a bit, then we need to change it for others so that other would have different
07:51permissions.
07:52Now, I told you that I'll also give you a trick that might help you to identify
07:56which user Apache is running as. If we run the command ps aux, that will give
08:01us information about the processes that are currently running. If we then put a
08:04space and the upright pipe, so that's just straight up and down bar, space grep
08:11and then httpd. That will look for the web server process it's running. It will
08:18usually be called httpd and if we do that it will search for lines that contain
08:23that, and you will see that we got a couple back, this is the important one
08:26here, which is that I have my web server running as WWW. You can ignore the
08:32underscore that's in front of it. What's important is that WWW that is the user
08:36that my web server is running as.
08:38So now that we have understand the fundamentals of users and permissions,
08:42in the next movie let's look at how we can actually change the users and the
08:45permissions on a file.
Collapse this transcript
Setting file permissions
00:00Now that we understand the fundamentals of file permissions, let's talk about
00:04how to change those file permissions from the command line. And we're going to
00:08be making use of two Unix commands: chown and chmod. So those are the ones
00:13we're going to be using to change the ownership and to change the permissions.
00:16Let's see how that works.
00:18So here I'm at the command line where we left off before. I'm still inside the
00:21btb_sandbox. I'm also just going to real quick go into the sandbox and create a
00:25new file that we can use to work with here and not mess up our other files.
00:29So I'll open up TextMate and open a new file and I'll just say 'This is a file
00:35for testing file permissions.' And then I'll save it in that btb_sandbox folder
00:42and we'll call it file_permissions.php, and it didn't actually have any PHP in it
00:50but just to keep at the same as the other files, we'll give it that extension.
00:53So here is file_permissions.php, we see it right there. Let's do our ls - la trick
00:59again to do a list and then we'll now see file_permissions.php shows up here
01:03and we can see it has the same permissions. Read and write for the owner,
01:07which is me Kevin, and for both the group and other it has the ability to
01:12read the file, which allows our web server to read it, which allows it then to
01:16serve up what's in the file.
01:17Now just to be clear when we talk about executing a file, that's not executing it
01:22on the web server. All the web server has to do is just to be able to read-in the script
01:25and it will do whatever is in the script. When we're talk about executing,
01:28we're talking about having more of a .EXE file or something that we can actually run
01:33from the command line. Execute is not going to play a big part when we're
01:36working with a web server. Either we can read or write the file, or we can't.
01:39You will remember from the last movie I was able to find out that my
01:43Apache was running as WWW, and that may be true for you. It also may be Nobody
01:48or Apache or something else. I'm going to go ahead and just show you how to
01:52change file permissions to have a different owner. And I'm going to do that
01:55with that chown command, but before I do that I'm going to type in sudo.
01:58Now, you may have use sudo a few times in the past and not really known what it did.
02:02It basically says do this command with the highest level permissions that
02:07the system has. So if I'm allowed to be a sudo person, if I'm allowed to have
02:11that superuser ability, that's what the su stands for superuser, then I'll have
02:16those superuser permissions.
02:18So with top level permissions, try to change the owner to www for
02:26file_permissions.php. And it came back. It didn't give me any response.
02:33It just did it. If I type ls - la though, we'll now see that it is changed the owner to
02:39www. So now the ownership has changed, www has read and write permissions.
02:45Kevin just has read permissions. So we have changed who is the user for this file.
02:52Now we can do the same thing to change permissions. We can say sudo and then
02:57chmod and then we're going to pass in the permissions that we want. And there
03:01are number of different ways we can do that. We can use the symbolic notation
03:04that we saw before, that r, w and x, but I'm going to do with the octal
03:08notation that we have talked about.
03:09I am going to go ahead and for now just say 777, so you will see what it does
03:13with file_permissions.php. All right, now let's do ls - la and see that again.
03:21And notice now that 777 opened it wide up so that everybody can read, write and
03:26execute. It doesn't matter who the owner is. Everybody has the ability to
03:31access this file.
03:32Now, we can have something that's a little more locked down than that.
03:35I'll just simply change this to be 7, let's say 44. Actually it's 644 is what we had
03:41before. I'll go back to that first. 644 and you will see that now it's back to
03:46what it was. This is 6, this is 4 and this is 4. So now I have set it back to
03:51what it was.
03:53Let's try changing it so that Kevin doesn't have access anymore. So let's just
03:56say 600. Kevin might be part of staff. So let's go ahead and make sure that
04:01staff also doesn't have access. So it'll be 600. The www user will still have those
04:07read and write privileges. And now let's just try opening that file up.
04:11So I'll come back here into my file system. I'll double-click on file_permissions.
04:15You see it comes up blank and I'll type hello and hit Save. It says oh, it wants your password.
04:21So it won't let me do it because I don't have enough permissions
04:25and it doesn't allow me to see what's in there. So the important point that
04:27you need to take away from this is that in order for your PHP to work
04:31successfully, you need to make sure that the file is readable.
04:34Then the web server can read it in and do whatever it ask it to do.
04:38However, now that we're about to start doing uploading of files, we're also
04:41going to need to have directories that are writable, so that we can actually
04:46write to them. And when we start doing things like log files, we're going to
04:49need them to be both readable and writable. So that we can add entries to a log file
04:54and read back what's there as well.
04:56Now in addition to being able to issue command line instructions like chown and
05:00chmod, we can do the same thing from inside PHP and that's what we'll look at
05:05in the next movie.
Collapse this transcript
PHP permissions
00:00Now that we've seen how to manipulate file permissions from the command line,
00:03I want to just see how we can do that in PHP. Before we can get started on that,
00:07we first need to talk about something in PHP called safe mode.
00:10At the beginning of this title,
00:12we created a my_phpinfo file that just simply brings up the PHP info script,
00:18and we can bring that up in a browser and take a look. So here we are at the
00:22main page for PHP info. If you do a search for safe_mode, you'll see that it
00:27comes up and gives us safe_mode for me is off.
00:30Now yours may say on. It's not so important whether it's on or off. It's that
00:34you know how to change it and what it does. The way that you change it is
00:37you go into your php.ini file and you turn it on or off. Then you just restart your
00:42web server, so that it reloads those new changes for PHP. That's how you turn
00:46it on and off. What safe mode does is that when safe mode is on, PHP checks to
00:51see if the owner of the current PHP script that's running matches the owner of
00:57the file that you want to manipulate.
00:59So if safe mode is on, we don't have the ability to manipulate files that
01:03we don't own. Now this is a feature that was added mostly for shared hosting
01:07environments. It's eventually going to go away in PHP. It's not strictly
01:11necessarily for you to have it on, certainly in your development environment
01:15and even in your production environment. But if you're going to be manipulating
01:18file that you don't own, you will need safe mode to be off.
01:22Now that we know about safe mode, let's create a file where we can start
01:25working with our PHP, so I'll open up TextMate and I'll make a new file and I'm
01:29going to save it in my btb_sandbox and I'm going to call it file_changer.php.
01:36Now that may sound like an odd name, but what I'm after here is that this file
01:40is going to be where we manipulate another file and the other file we're going
01:44to manipulate is going to be file_ permissions, the one we're working with from
01:47the last movie.
01:48So file_changer will be the currently running script, file_permissions will be
01:53the one that we're going to manipulate. Let's take a look from the Terminal.
01:58Remember, I said you could do ls - la, I'm also going to use that upright pipe
02:03followed by grep and then file_. This will come back and just give me the lines
02:10that are related to file_ in the name.
02:12So we can see the basics file, we're not interested in that one. But we can see
02:15changer, and we can see permissions. Now for me, changer is owned by Kevin. WWW
02:23though owns file permissions because we changed it to be that. You may have
02:26changed it back or it may be something else.
02:29So if we have safe mode on, file changer will not be able to make any changes
02:33to file permissions, because they have different owners. It doesn't matter what
02:36permissions are set over here, even if we're allowed to execute things, PHP
02:40will intervene and say sorry, I'm not going to let you do that. Instead, I
02:45think it's better to have safe mode off, and then we can control which things
02:49we allow PHP to do by using the file permissions.
02:53So to share with us, take a look at the fileowner function. So, fileowner, and
02:58this will tell us the owner of a file. We're going to say file_permissions.php.
03:03That's the file that we want to look at. Now notice here, I just provided
03:07simply a string with the file name. It's going to assume it's in the same
03:10directory. If it was somewhere else I could say ../ to get it to go back a
03:14directory or I could use an absolute path, we saw how to do that with file+ and so on.
03:20But it's going to just assume it's in the same directory. So let's bring this
03:23up in a browser and see what we get, if we ask for just the fileowner. So here
03:26we're with file_permissions and I now want to run file_changer. It came back
03:31with 70, now that's not particularly useful, it didn't give me www, instead,
03:35what it gave me was the ID of the user, because that's what is stored there and
03:40that's what's easiest for it to find.
03:41Now we can compare IDs between this file and a different file, but in order to
03:46find out the name, it's a little bit trickier. And what we're going to need to
03:49do is make use of a library that is probably not installed on Windows and even
03:54may not be installed on a Linux, Unix of Mac machine. It's called the Posix library.
03:58So if we have Posix installed, then, we can do it a little bit differently.
04:06Instead, we can say that the owner_id is equal to this and then we'll pull back
04:15an owner_array by saying posix_ getpwuid. Then I'll get the user ID from the
04:26password file for the owner_ id. So it looks it up for us.
04:33Then once we get that array of information back about the owner,
04:37then we'll pull out the part that we want, owner_ array, just the name, and you can take a look
04:43at the full array if you want to see what else it gives you.
04:45So let's try that now.
04:46We'll go back to Firefox. We'll reload it and you'll see we get the www. I'll
04:50go ahead and just put in echo br, just so that we have nice break there. Now
04:56that we have the owner name, we might want to now change the owner.
04:59For example, from www to Kevin or to your name.
05:04So we saw that out before with chown, we still have chown available to us in
05:08PHP, but it's going to be so Problematic. It's basically unusable.
05:11I'll show you why. We first need to provide the file name that we want to change the
05:15ownership of, and then we need to provide the new owner name. So for me
05:18I'm going to put in Kevin, you can put in your name, whatever you had before or a
05:21different user. Nobody is also probably a user you could use.
05:24So I'll save it. Now before I try this in a web browser, let's go ahead then
05:29and do the same echo statement back again just so we can see who the owner is
05:34after we've done the chown statement.
05:36Now, keep in mind before I run this, that safe mode is off for me. So that's
05:41not stopping us from making this change. You'll remember if we look back at the
05:46Terminal that this file is set to both read and write for anyone.
05:50So read and write is not the issue, it's not a permissions problem. So let's
05:54now switch back over to Firefox and let's try it out. file_changer.php, and it
05:59comes up and its says Warning, operation not permitted. Now, the reason why
06:04it's not permitted, you can see in the documentation for chown on the php.net website.
06:09It attempts to change the owner of the file, but only the superuser may change
06:14the owner of a file. That's a pretty big restriction. You remember when we did
06:17chown from the command line, we typed in sudo. That made us temporarily the
06:21superuser so that we had superuser privileges.
06:24Well, PHP insist that we always have to be the superuser if we're going to
06:29change the owner of the file. That means that our web server has to be a
06:33superuser. Now that creates a pretty big security issue for us. If we let our
06:37web server have those top- level access privileges.
06:41So for that reason, I don't recommend it, and it think that makes chown
06:44virtually unusable in PHP. So it does exist, you do have the ability to use it,
06:49but I don't recommend it. Instead, we're going to want to stick with chmod and
06:53changing the privileges so that the privileges allow the right person to access
06:58the right file.
07:00So let's switch back to our file_ changer and I'm just going to make a note here
07:04that says, "chown only works if PHP is superuser, making webserver/PHP a
07:19superuser is a big security issue. But unlike chown, we can use chmod. So let's
07:27see how we can do that. First, let's see what the permissions are.
07:31So we'll say echo, fileperms for file permissions and then we're going to use
07:37the same file, I'll just copy and paste. Fileperms and let's see what it gives
07:45us back. Let's go to Firefox, reload. You'll see it gives us 33206. Now that
07:51 doesn't translate to anything that we've talked about so far, 3s were not part
07:54of that code that we're using to change to octals and this is not a symbolic
07:58notation, but this is a decimal representation.
08:02So in order to make it usable, we need to use a simple function called decoct,
08:09which is basically to convert from a decimal to an octal. So this is one of the
08:13only times you're going to use it, decoct and surround it. Then we'll come back
08:18and we'll say all right Firefox, now give it to me, and it comes back and says
08:22100666.
08:24Now the important part is these last four numbers. The last 3 is what we're
08:28used to seeing as an octal. That fourth one is also going to be something that
08:31PHP is going to want us to use. In fact, if you really want to get just the
08:36important part, you can use substring function wrapped around there, 2, and
08:42then when we go back to Firefox, it will return just those four characters of
08:46the file permissions.
08:47Now that we have that, let's try and use chmod to change it. So we're going to
08:51change it on file_permissions.php and let's go ahead and say that the file
08:57permissions ought to be 777. Now there is one big change that we need here.
09:02We need to put that 0 in front of it. So PHP is always going to want to have that
09:080 in the first place.
09:10So, 0, and then the octal number that we're used to using. So let's try that
09:14and then after it's done, let's echo back the change. So we'll see the
09:18difference. So now we'll switch back over to Firefox and we'll try it out. So,
09:22I'll hit Reload and we came back to same thing. Let's reload it one more time.
09:26There it goes. Now we see the change took place. So the change permissions did
09:30take place, we just had to reload our page an extra time to be able to see them.
09:33Now, it's not very convenient to have to check this octal to figure out whether
09:37something is readable or writable to you. Instead the better way to do it is to
09:41use is_readable and is_writable and use those as test for whether or not
09:50we can read or write to the file. So let's paste in the file name there,
09:53so is it readable, or is it writable?
09:55It's a Boolean expression. So we want it to return yes or no and I'll just put
10:01that it down here as well. We'll need our semicolons and we'll need to echo the
10:06value just so that we can see it. So that will just give us a quick is that
10:09file readable, is that file writable, and let's just grab our br tag here just
10:16so that it's nice and clean. All right, let's try that out.
10:18So is it readable or is it writable? Yes, it is readable and it is writable,
10:23and we've change this now to be something like 444, save it, let's go back to
10:29Firefox, reload it, yes, it is readable, no, it's not writable. Now we didn't
10:34see the file permission change there. If we reload a second time,
10:37we'll actually see it. It had cached it.
10:39So, it did right away know that whether it was readable or writable. So,
10:44is_readable, is_writable are the methods that we'll use to find out if
10:46something is readable or writable, and we'll use chmod if we want to change the permissions.
Collapse this transcript
Accessing files
00:00Now that we understand permissions and how to determine whether a file is
00:03readable or is writable, we're ready to actually do the reading and writing,
00:07and the first step in doing that is learning how to access files in PHP.
00:11The PHP function that we're going to be focusing on primarily is going to be
00:14fopen. So we're going to open up a file, we're going to provide the file name
00:18and we're going to tell it what mode it should open it in. We'll talk about
00:22modes in a second.
00:23One important thing to note is that fopen opens up a file whether it exists or not.
00:29So it will create it if necessary. Now just because it's called open,
00:33it doesn't mean that the file has to exist already. We can say fopen and provide a
00:38file name that doesn't exist, and assuming we have provided the right mode to it,
00:41it will create the file if it doesn't already exist. So it will either open
00:46the existing file or it will create a new one. The same command will work for both.
00:50So now let's talk about modes. The file access modes that we have the option of
00:54passing in are r, which is read from the start of the file. This is just
00:59reading only and the file must exist of course if we're going to read from it.
01:03So that's going to be reading data in from a file that's already on our server.
01:07The second two are going to be our two write methods. The first one is going to
01:10erase anything that was in the file if it already existed, or create a new file
01:14if it didn't, but we're basically going to be starting with the blank file and
01:18we're going to be at the beginning of the file ready to start writing, and
01:21the third one is append or write to the end.
01:23So that's going to be useful for something like a log file where we just need
01:27to add one new entry and then exit the file. In that case, the w method would
01:31not have been suitable because it would have truncated everything that there before.
01:35Just wiped it out.
01:36Now there is a fourth mode that I want to mention to you which we won't use a
01:39lot but its x, and that is write from the start and the file can't exist.
01:44So essentially, what that does is keep us from accidentally overwriting another file.
01:49It says start writing a new file, but object if this file already exists,
01:54do not overwrite it.
01:55Now all four of these modes also offer an alternative version. Instead of just
02:00r for reading from a file, what if we want to read and write from the file
02:04while we're in there? Well, for that we have a plus version. So for the read,
02:08we can both read and write if we put the plus after it. For the w+, it's going
02:12to truncate us, put us at the start, but then we can go ahead and read and
02:16write from there and append will put us at the end of the file but also enable
02:21us to both read and write from it and the same is true for x.
02:24So those plus versions are the ones that let us move around in the file and
02:27read a little bit, write a little bit, and then keep moving on. If we're just
02:31going to be reading though, we're just going to be writing, we want to stick
02:34with the non-plus versions.
02:36Now before we actually put fopen into practice, there is one more thing that I
02:39want to make sure I caution you about, which is file line endings. There is
02:43another difference between the two platforms, Windows and then Mac, Linux and
02:47Unix, is the kind of line endings that end each line of a file.
02:51Windows uses, \r\n. Now you may say, well, I've never seen that in a file.
02:56A lot of times, they get suppressed and hidden by your word processor or whatever you are
03:01looking at, but that how it knows to wrap around is that it has those characters
03:05in there and then it just hides them from you and just goes ahead and moves to a new line.
03:08Well, Mac, Linux and Unix use \n instead, so you can see how if we're reading
03:12in a file that has the wrong line endings, it might cause problems depending on
03:16which platform we're on.
03:17So there is an additional mode modifier that we can pass in as well as the r,
03:22the w, and the a, and the x and that is either t or b. Now b is binary mode
03:28which says basically don't translate. Just take what I give you and write it to
03:32the file without making any changes and b is in the default on all platforms
03:35since PHP 4.3.2. Before that, it depends on exactly which platform you are on,
03:41which version of PHP. You couldn't really be sure, but for a while now it's been
03:45standardized on b.
03:46Now t is really for use by Windows users. If you need to use Windows line endings
03:52when you are writing a file, so that let's say another Windows
03:55application can open it up later, you'll want to use the t modifier, and that
04:00will then make sure that everywhere you have set /n in our PHP script, it will
04:04quietly just put down \r\n for you so that it's ready for your Windows application.
04:10Now the same thing, if a file was created originally in a Windows application,
04:14you can use t to translate and make sure you get those correct line endings.
04:18So I just want to make sure that I at least tell you about that so that if you are
04:21having problems on Windows, with having the wrong line endings,
04:24you'll know what the solution is.
04:25Now let's get some experience using fopen. So I'm going to open up TextMate and
04:30let's create a new file and I'm going to save it in my btB_sandbox as
04:36file_access.php. In this file, we're just going to concentrate on getting
04:41access worked out.
04:43So we already have talked about the fact that it was going to be fopen that
04:46we would be using. So let's specify the filename and let's just call it
04:51file_test.txt. It's a nice simple name so then we're going to want to pass that
04:57file name in to fopen. Then we're going to need to pass in the modifier.
05:02So in this case, we're going to create a new file called file_test and write to it.
05:06So I'm going to use w. If I had used r, it would fail because file_test
05:10doesn't exist but here is also where I could pass in b or t if I wanted to add
05:16those additional modifiers or plus, but for now I'm just going to be using the w,
05:20and fopen also returns a handle as a value.
05:24Now you remember we talked about handles with the database connections.
05:28When we did database connection to MySQL, it returned a handle and the reason why that
05:33handle was useful was because then we could close it and that's exactly what
05:36we're going to do here as well. We're going close our file by referencing its
05:40handle. So it just a reference to the file that we have opened so that we can
05:43continue to talk about it after it's opened.
05:46Now it's a good practice to always close your files. PHP will close all files
05:51at the end of the code execution on its own, just like it closes the database
05:55connections but you want to close them yourself so that you don't accidentally
05:58write to the file again when you don't mean to. It's just a good practice.
06:01If you are opening up the file, let's go ahead and close it when we're done;
06:04if we need to reopen it, we can reopen it and so on.
06:07So let's go ahead and try this and it's going to give us some problems but
06:10it will illustrate a couple of points that I want to make. So I'm just going to
06:13save file_access and I'll open up Firefox and we'll go to
06:19localhost/btb_sandbox/ and it'll be file_access.php that we'll load up.
06:26Now instead of working, it gave us an error saying that fopen failed to open
06:31stream. That means that it failed to open the file; the stream is just the data
06:34stream where it's going to write to the file. So the permission was denied is
06:38the error why and so therefore, fclose couldn't work because it had an invalid
06:42resource because we never opened it up.
06:44So this raises one issue that I want to jump to right away which is that it's
06:48always a good idea, I think, to bracket this inside if statements. So we say if
06:54the handles succeeds, then what do we want to do? And in this case, we'll just simply close it.
07:00That's all we want to do. If not, then we'll just have
07:06something like echo "Could not open file for writing."
07:14So I think that's a really good habit to be in because it's going to prevent
07:17some of what happened here. Now if I do it, it says it "could not open file for writing."
07:20I get something that's a little more meaningful.
07:22Now I'm still getting my errors because I'm in development mode and I told my
07:26PHP file to show that to me but in production, I would still be able to see
07:29something like "could not open file for writing" and we can also take a different
07:33action here if we wanted to. But now let's deal with this permissions issue and
07:36actually fix what's going on here with this permission denied.
07:39Now if it did work for you, than that's great. But if didn't, like for me,
07:43and I'm guessing it probably didn't, you will need to go to Terminal and in
07:47that btb_sandbox file, we need to see what the permissions are for the
07:50directory that we're trying to create this file in. We talked about
07:53permissions, so I'm going to scroll up here at the top. This is the current
07:56directory we're in. It's the period. dot-dot is the directory one back from here.
08:01Period is this directory that I'm in right now, btb_sandbox. These are
08:07its permissions.
08:08So you can see that as the user, Kevin, I have the ability to read and write files to it
08:13but the web server, which is not running as Kevin, it's running as www,
08:18doesn't have enough privileges to write. It can only read from these files.
08:22So we need to give it privileges on this directory so that it can do that
08:26and you remember how to do that.
08:27I don't think I need to tell you but we'll do it together. sudo chmod and we'll
08:32just go ahead and make it 777 so it will open up wide up, and you also could
08:35change the owner if you wanted. I'm just going to open it wide up so that
08:38this directory now is fully able to be read and written to or execute anything
08:43that's in it. And the way I talked about this directory, that I could
08:46either navigate back a directory and then say okay, the btb_sandbox file, or
08:51I just can use that period and that will say this directory that I'm in right now.
08:54And it wants my password because I did the sudo and then let's just do
08:59ls -la one more time. We'll take a look back up here and sure enough,
09:04this directory now has rwx, rwx, rwx. So now, it is a writable directory.
09:11Let's switch back and let's just try our file_access again and there it is.
09:15It worked fine. If we come back over here and take a look, we should have gotten
09:19file_test.txt and there it is. It created it.
09:22So it's important I think to use that if/then statement, it's important to
09:26always close your files and you want to make sure that any file that you are
09:29going try and write to is going to be writable. You just need to make sure that
09:33the file itself is readable. Then in case of writing, when you make sure that
09:36the directory we're going to write to has permission to write to it. In the
09:40next movie, we'll take a look at how we can actually write content into the file_test.
Collapse this transcript
Writing to files
00:00In this movie, I'm going to show you how to actually write data to the files
00:03now that we know how to access them, and once you have the accessing done,
00:06writing to them is dead simple.
00:08Now this is the file_access.php file I was working with. I'm just going to save
00:12it as a new file just so we can keep track of the different stages that we're
00:15working on. So I'm just going to do Save As and instead of file_access,
00:19I'm going to call it file_write. There we go.
00:23Now I have the other one saved to refer back to and we can go ahead and make
00:26changes here. So I'm still going to work with the w mode. I'm just going to
00:30make note here that this is going to overwrite anything that was there before,
00:34just so that I remember, and we already have the close.
00:37What we need to do now is actually write to the file and it's super simple.
00:41It's just fwrite and then the handle and then whatever we want to write, abc.
00:48And just to make a note here, that's going to return the number of bytes that
00:53were written or false, and it's up to us whether we want to capture that or not.
00:57We can also make an if then statement if we wanted to check and see
01:01whether it succeeded or not.
01:03Generally if you can open the file, writing goes ahead and takes place. So
01:06there is no real reason that we need to capture that data, we usually just go
01:09ahead and write the data and then close it when we're done.
01:12So let's go ahead, and to give this a shot, let's open up our web browser and
01:16this one is going to be called file_ write. So there it ran, we didn't get any
01:21data there. We haven't learned how to read from the file yet. So instead,
01:24we're just going to come over here to file_ test.txt and open it up and there is our abc.
01:28So there it is. It did go in.
01:31So if you wanted to write more to it, we can do the same thing. Let's say
01:34fwrite and then the handle again and this time, we're going to pass in 123.
01:39So we'll save it. Again we're going to be overwriting that file that was there,
01:45and let's hit Return. We'll open it up. I'll test. Now it has abc123.
01:51So you will notice that when we issue another write statement, it just picks up
01:57where it left off and that's going to introduce us to this idea of the pointer.
02:00It works like a cursor. So while this file is opened, it puts the pointer at
02:04the beginning of the file and now it's waiting for us to type, and when you do
02:08a fwrite, it types abc for us and then the pointer is sitting there right after
02:13the c just like the cursor blinking, and then when we say fwrite again, it
02:18writes the next bit of text.
02:20So keep that idea of the cursor or the pointer in mind because we'll be looking
02:23at it again in a moment. Now more often and not, I would say that you typically
02:28construct all of the content that you want to output. So let's say 123, we'll
02:33put in a new line 456.
02:34There we go and then we'll simply just say all right after we've got all of our
02:40content put together, pushed into a variable with all the line breaks, then
02:44we just do write, and we probably would even have a first one here, we would just
02:48simple construct everything and then, say write it to the file, close the file.
02:52So that's a more common way to work.
02:54I want to show you this also with the line endings because it raises another
02:58point which is the double quotes matter (with) and I'm going to say /n, but
03:03it's really with any of those special control characters. Single quotes will
03:07put in a literal /n, but the double quotes say be aware when you are looking at
03:13the string that there might be some special characters like line returns.
03:17So the double quotes are important so I'm going to save that and let's go ahead
03:21and just to prove ourselves it worked one last time, we'll do file_write and
03:25then we'll go back and open up file_ test, and there it is abc123 and then 456
03:33on a new line.
03:33Now there is one thing I want to caution you about here is that you might be
03:38tempted at some point to do something like a chmod, let's say chmod and then
03:43the handle and then let's say 0777 and that would make the file readable,
03:49writable, and so on.
03:51Well, be careful with this because the handle doesn't work with chmod, the
03:55handle only works with these that begin with f: fwrite, fopen, fclose. Those
03:58are the ones that use the handle, this one is the actual file name so in that
04:02case, this would actually change it to the write permissions.
04:06So just be careful with that the handle is not universally used, it's only
04:10really in these simple cases. Now if all of that seems a little bit laborious
04:14to go to the process of every time writing a line and then the handle and
04:17everything, there is also a shortcut. So I'll just show you, it's called
04:20file_put_contents. So we have a file, I have the contents all here together in
04:24a single string, then I can use file_ put_contents, you pass in the file name,
04:30pass in the contents, and it's a shortcut for opening the file, writing the
04:34contents, and closing it.
04:36Now that's going to overwrite by default. So be very careful because it's going
04:39to just blow away anything that was there before with this new stuff and I went
04:43ahead and captured the size of what it wrote just so that I can echo it back,
04:47just to show you how that works.
04:49So let's try it. It's going to do the first writing at the top and then it will
04:52do the file_put_contents, and we can just see the difference. So there we are,
04:55file of 11 bytes was created and if we open up file_text now, you will see it
05:00only has this 111222333, which was what I wrote here in this content. All of
05:05these got wiped away.
05:06So this is the shortcut for doing all of those steps. If you are just simply
05:10going to write a whole file, you can use this instead of going through all of
05:14those steps. In the next movie, we'll take a look at how we can delete files.
Collapse this transcript
Deleting files
00:00You have seen how to create and write to files. Now I want us to see how we can
00:04delete files. Deleting is super simple as long as we keep two things in mind.
00:08First, we need to close the files that we want to delete first. We can't delete
00:12opened files. So we have to have that fclose on any file we want to delete.
00:17So if we have opened it we have to close it. If we never opened it, it's not an issue.
00:20It's already assumed to be closed.
00:22Second, we must make sure that we have write permission on the directory or the
00:26folder that contains the file. So in the same way we have to make sure that
00:29that directory was writable before we could create the file, we have to also
00:33make sure that it's writable before we can delete the file.
00:36Now in our case, that's already going to be true but I wanted to mention it
00:39because it can be little counterintuitive because you may think, oh, well,
00:42I have write permissions on the file itself, I ought to be able to delete it.
00:47But it's actually the directory that contains it where it makes a difference as well.
00:50So just keep that in mind.
00:52In order to test it out, we'll delete the file test.txt that we created
00:56earlier. We'll open a new TextMate file and we'll go ahead and save it as
01:00file_delete.php and we'll put some PHP tags in there. Now deleting it is as
01:11simple as this one command, unlink.
01:13Now I know unlink may not sound like what it's doing is deleting it. That's how
01:18you do it. The same way you unset a variable, we unlink a file. So we'll save
01:22that and let's just try it out. Let's get rid of that filetest. We can always
01:25create it again if we needed to. We'll go into Firefox and file_delete. There it is.
01:33Let's take a look and see and our test_ file is now gone. It's not there anymore.
01:39So as long as you keep those two caveats in mind, deleting file is super
01:43simple. In the next movie, we'll talk more about this idea of the file pointer
01:47and how we can move the cursor around inside our file.
Collapse this transcript
Moving the file pointer
00:00You remember back from the movie where we learned to write to files that I
00:04talked about the idea of the file pointer, where it's like a cursor in a word
00:07processor that we can type and then it's the cursor sitting there waiting for
00:12us to type some more.
00:13Well, like a cursor in our word processor, we also have the ability to move
00:16that pointer around inside the file to write to different places within the
00:21file and that's what we're going to see how to do in this movie.
00:23So let's open up a new file in TextMate and I'll go ahead and save it as
00:28file_pointer.php and the first thing we'll need to do is the same kind of
00:36create file and write to a file that we have done before, nothing really that
00:40special there.
00:41So in order to find out where a pointer is right now, after we have done this
00:45writing, we can use ftell. We'll pass in the handle again and that will return
00:51the position. So I'll just call it pos. That's the position of our cursor or a
00:56pointer after having typed the 7, 8, 9 there.
00:59So now we can use that as a reference for moving around. We can do that with
01:04fseek. Now we're not doing a search, what we telling it is move to this new
01:09location, seek this new location for us. So handle and then we also need to
01:15tell it what position it's going to go to.
01:16So let's say pos and let's just say -6. So it will take the current position,
01:22-6, so it will move back six characters and once we do that then we can write
01:28something else. I'll just put in abcdef. It's so common that if we want to go
01:32back to the beginning of the file we also have rewind available to us. And just
01:37pass in the handle and it will rewind back to the beginning of the file and
01:41let's just put in something else here, xyz.
01:45So let's go ahead and just try this and see what happens. And so what we're
01:49doing is we're writing a little bit to the file, finding up a cursor position,
01:52moving back six characters, typing something else, going back to the beginning
01:56of the file and putting in something else and then closing the file.
01:59So let's try it. Let's go back to Firefox and you will remember that this is
02:04going to actually create the file for us. We deleted it in the last movie. But
02:08it will create a new file called filetest.txt and if we open it up, look what
02:12we get. We did get the moved around text. But notice that it overwrote what was there.
02:19So just to be very clear, this has nothing to do with what mode what we put it
02:23in. It's not because we're w mode or we have x or a anything like that. This is
02:28the behavior. When we move around the pointer that cursor will over type. So if
02:32we want to capture what was there, we have to first read that data in, hold it
02:37in the variable and then re-output it at the end.
02:39So if we really wanted to put xyz at the beginning and not destroy what was
02:43there, then we have to capture it, put this in, and then re-output what was
02:50there before. So that's the first thing that I want to caution you about. So,
02:53Beware, it will overtype, okay, so that will remind us about that.
03:00The second thing that I want to point out here is that those modes do matter a
03:04little bit because the a and the a+ modes, the append modes, will not let us
03:09move the pointer. They put it at the end of the file and they force it to stay
03:13at the end of the file. They force us to append.
03:15The R and the Ws are ones that allow us to move around and read and write from
03:20different places. So if we want to be able to append but then we might also
03:25want to jump back to the beginning. We need to use something like r+ as one of
03:30our options and then we can go to the end of the file, write something, jump
03:34back to the beginning and write something else.
03:36So those are just the two things that you need to be careful of. But with that
03:39ftell, fseek and rewind, you will be able to move around to different points in
03:43your file and write data.
03:45Now typically we're only going to want to write it either at the beginning or
03:47at the end or just write the whole file. But at least, now you know how to move
03:51that pointer around and the way the pointer works.
03:53In the next movie, we'll take a look at how we can read back data that was
03:56previously written to a file.
Collapse this transcript
Reading files
00:00Now that we have seen how to write file and how to move the file pointer
00:03around, we're ready to learn how to read back information from files.
00:07So to start this out I want to open up file_write.php, just so we have that as
00:11a reference for the steps that we used to write a file because that's going to
00:14be very similar and then I'm going to also open a new PHP document and
00:18I'll save that in my sandbox and I'll just call it file_read.php.
00:25So just like before we'll have our PHP tags and let's go ahead and specify the
00:29file we want. We'll have it be the same thing, filetest, again. Opening the file
00:34is going to be pretty much the same thing except that instead of overwriting,
00:38now we want to read and that's that r option.
00:42So we'll open it up. I'll go ahead and close my curly braces so I don't forget.
00:47And then inside here we need to actually do the reading and just like we used
00:50fwrite over here, we're going to have something similar. We're going to have
00:54fread that we'll read back in. So we'll pass in the file handle that we created
01:00and the other option that we need to pass in is argument for fread is how many
01:04bytes do we wanted to read. I'm just going to say three for now. And then I'll
01:07just make a note here that each character is one byte.
01:13Now that's true in typical English language. We have one-byte characters.
01:18In something like Chinese, it's multi- byte characters, so it is not necessarily true.
01:22But for the English language with a typical Roman alphabet,
01:25each character is going to be one byte long and then the other thing of course
01:29we need to do is -- we don't want to just read it, we want to do something with that read.
01:33Now we could just echo it out. That's perfectly valid. But I'm going to go ahead
01:36and just capture in a variable content and then we want to, of course, make
01:40sure that we do our fclose that we normally do to close up the file once
01:44we're done with it.
01:45So now we have read three bytes in or three characters and we have assigned
01:49them to content. So in order to take a look at that we could just simply put in
01:54echo content and we'll be able to see those results back. Let's try that out.
01:59So we'll go into Firefox, local host/b2b_sandbox and we'll open up
02:04file_read.php. And sure enough it comes back with xyz. And I'll just move this
02:10out of the way so we can bring up filetest.txt. Yours might have something
02:14different. For me it brought back these three characters. Those three bytes.
02:19If we were to bring back more, let's say we brought back six characters--
02:24let me close that up-- Firefox reloads the page. You will notice that it all comes
02:27through as one line. It didn't break to a new line. That new line character is
02:31actually in there as part of the output.
02:34What we need to do in that case is to actually use to nl2br tag and that is
02:41basically saying that we're going to take each new line and turn it into a br tag
02:45so that HTML will show it properly and now we can see the break as
02:49we would expect. So instead of just getting this, we end up getting the two-line version.
02:55Now I'm sure you are wondering what about if we don't know how many bytes a
02:58file is? We want to still be able to let's say read an entire file regardless
03:02of how long it is. But with that we can use filesize. So fread handle and then
03:08we'll ask the file, tell me what your file size is. How many bytes are you?
03:12And so filesize comes in useful by telling us the total number of bytes.
03:15We will now read the file until we get to that total number of bytes, then
03:19we'll know we have everything and then we can do the same echo back and let's
03:23go ahead and put in the nl2br. We'll try that out and now we get in the entire file.
03:29Now back over here on the file writing, we had file_put_contents and that was a
03:34shortcut for us that would do the open, the writing and the close. Well,
03:39we have the same kind of thing that we can do for reading and that is
03:43file_get_contents. So it will say get the contents of this file, get everything
03:47there is. It takes care of filesize and all that for us, reads to the end of
03:51the file and then we have the ability to just echo that back. If we switch back
03:55over to Firefox and we reload the page, you will see that it did.
03:57I didn't put the nl2br there, but we know what that does.
04:01Now the last thing that I want to make sure that I'll show you is incremental reading.
04:05Now we have already seen how we can do incremental reading by reading
04:08a few bytes but another thing that's really useful is to be able to read
04:11one line at a time. So for example, if we had tabbed delimited data,
04:15so we're looking at an export that's been done of a attendees or products something like that,
04:22we could take that value and we can look for the first name, the last name and
04:25everything as we parse through each line, and each one has a line return at the end.
04:29So it comes back. So we obviously want to just get a line essentially and
04:33in order to do that what we use is fgets content = fgets($handle) and that will
04:42then get one line of the file and that's the maximum amount that it will retrieve.
04:47Now obviously in a case like this, we're going to want to not just get one line back
04:51perhaps but still go through and get the entire file and the way we can
04:56also do that is by using while statement: while, not f for file, eof for end of file.
05:04So while we're not at the end of the file and we need to pass the handle
05:08again so that it knows which file we're talking about, then go through and
05:13perform this loop.
05:15Here we go and of course content then will need to be built up over time.
05:19We don't want to just keep replacing it and we know how we could do that with
05:22something append. So content starts up being equal to an empty string and
05:26each time we'll add each line to it.
05:28Now obviously if we're doing something like this we'll probably want to do some
05:30processing to it. We'll probably want to get this value, then parse it, then work with it,
05:35then store it to content. But what I want to just make sure that you saw
05:38was how this feof works, so that we can say loop through until you get to the
05:43end of the file. It essentially does the same thing as this filesize does, but
05:47instead of providing a number of bytes it just keep getting a line,
05:50keep getting a line, keep getting a line. If you hit to the end of the file then
05:54stop whatever you are doing. And that's all we need to be able to read in files.
05:57We'll go back over and just try it one more time here. We didn't actually
06:01output anything here at the end. Let's just do that one last time so you can
06:04see that worked too. Here we go and there we are.
06:08So now we know how about successfully write file and how to read from them.
06:12In the next movie, we'll take a look at how we can examine some of the file details.
Collapse this transcript
Examining file details
00:00To round our discussion about files, in this movie I want us to take a look at
00:03how we can get some of the information about the file details. We have already
00:07seen file size. We're going to look at meta information that we can get about each file.
00:12So we'll got to TextMate and we'll just open up a new window. I'll save it as
00:17file_details.php and that's in my btb_sandbox. We'll start our PHP tags.
00:25To start this off, let's go ahead and just put in the filesize, just so that
00:28we remember how to do that. So that it just simply the filesize and then we pass it
00:32in the file name that will echo back to us.
00:35The next one that I want us to look at is the modification times about files.
00:40There are actually more than just one number associated with this. There are
00:43actually three different ones and we're going to get them using filemtime,
00:47filectime and fileatime. I'll just put colons after that to clean that up a little bit.
00:52The filemtime is the last time that the content of the file was modified.
00:58So the file modification time. It's the content inside the file.
01:01We also have filectime. Some people mistakingly think that that's the creation time.
01:07That's not the case. It's the last changed time, when the file was
01:11changed. We don't have access to the creation time. So it's the last changed time
01:15and that's both changing the content or the meta data, the permissions,
01:20the owner, the group that it belongs to, all those sort of things that
01:23we learned how to do the chmod and chown. That includes those in filectime.
01:28The last one is fileatime. It actually keeps track of when a file was last
01:33accessed. So not only making those changes, like we do with ctime or mtime,
01:40but in addition anytime we read the file, anytime we read back the contents of the file,
01:44it updates that access time.
01:46So let's try all of those. Each one of them is going to take the file name as a
01:51argument and it's going to return back a UNIX time stamp. We saw how we can use
01:56string for time, right here, strftime and that will turn that time stamp into
02:01something that we can see. So let's just try that on this file name and see
02:05what we have got.
02:06Yours will almost certainly be different than mine, but you will be able to see
02:09the difference between the times that your file was modified, created, or
02:13accessed. So I'll just open up Firefox and let's go to file_details.php.
02:21So there we go. The size came back as 11. That's the first one.
02:25Then my modification times were all the same. So my file at 12/10/2008 at 13:05 is when
02:33my file was changed and updated.
02:36Now you may have different values or you may have the same value for all of those.
02:39One way that we can modify those times is with the touch command.
02:45So touch($filename) is going to say update those to the current time. We can also
02:52pass in some other additional arguments to tell it what time it should set it to,
02:55but what we're going to do for now is just say set it to the current system time,
02:59just sort of reach out and flip all of these times to be the current time.
03:04Then let's reecho it, just to see what time we get back. We'll go back
03:08and we'll reload the page.
03:09Now just reload it once at first and notice what happens. So I hit Reload.
03:14Now, the times didn't change, the times are the same. If I reload it again,
03:18watch what happens though. They changed. The reason why is because there is some
03:23caching going on. These values are being stored the first time it goes and finds them
03:28and touch does not change that. It does not flush the cache.
03:32So when we go here and we output it a second time, it's bringing up the cached values.
03:37So just because we touched it does not mean that we did not get the cached
03:41values back again. So we're getting old information at this point that is
03:43outdated. When we reloaded the page, then we got the new times.
03:48So I just wanted to show you by doing it twice, so that you see that it is a
03:51cached value. If you use touch, you may not get the right information here.
03:55You might be getting some old data back.
03:58So just to show you the difference, let's go in and actually open up
04:01filetest.txt and let's just make a change. Let's say ghi. Here we go and
04:07it's going to want me to put in my master password and that's because I'm not the
04:11owner of the file. WWW is the owner. So that's why it came up and asked me for that.
04:16You may need to do the same kind of authentication or you can do this
04:19with another file where you do still have permission to do it.
04:22So let's try that out now and just see now that we have changed the content,
04:24everything changed. If we instead go through and do a read, let's wait one
04:30second and after a good minute has passed, when you are pretty sure that a
04:35minute is over, we can do file_read.php. We'll read it and then when we come
04:40back and do file_details-- They are still updated so let's turn off our touch
04:45first of all. So that it doesn't touch them anymore. Let a minute pass, then
04:49run read and then you should see a difference. Now I'm not going to wait a
04:52whole minute and have you sit here and wait with me, but you can do that and
04:55you will see that access time is different.
04:56You can also try chmod and doing the chown and see the difference there and how
05:00that affects the different values. You might want to take off this touch,
05:03the same way I did just to make sure that you don't accidentally reset those values
05:08when you are trying to see the values change because of other actions you did.
05:12The last thing I want to show you about the file information that you can get
05:16back is pathinfo. So I'm going to take just the current file that I'm in and
05:20ask for its pathinfo. It's going to return an array. I'm going to call it
05:23path_parts, but it's an array of information that it gives back. Basically,
05:27what it does is it takes the information about this file and parses it,
05:31puts all the pieces into an array that we can retrieve. So here are the things
05:35we can retrieve back.
05:36I can ask for its dirname. That's the directory name that it's in and that will
05:40return the path all the way up to where the file is. basename will give me the
05:45name of the file with its extension. filename starting in PHP 5.2 will give me
05:50everything but the extension. Of course, I can ask for the extension just to get that part.
05:54So there are some variations you can look up on path name, some options we can
05:58pass to it, but this is essentially the way it works. It takes a file, parses
06:02its path into pieces and then we can retrieve just those bits of information
06:06and PHP knows how to do that for us. Let's just try that and make sure that
06:09it works fine.
06:11There we are. It gives us exactly what we would expect. I think this pretty well
06:15rounds out our discussion about files and we have learned how to write to files,
06:19how to read from files and how to change the permissions.
06:21Now we're ready to move on to talk about directories and that's what we'll do, starting
06:25in the next movie.
Collapse this transcript
Working with directories
00:00Now that we have seen how we can work with files, let's spend a little bit of
00:03time exploring how to work with the directories that contain our files.
00:07We'll start by opening up a new text file and I'm going to save that as
00:11file_directories and I'm going to still call it file, just so that they stay
00:15grouped with the other examples we have been doing called file. So there we are.
00:19We'll put our php tags in the start and now we're ready to talk about directories.
00:23Now, we have already seen a couple of directory functions before. dirname.
00:27We saw to get the name of the directory. And is_dir. We were doing is something
00:32a directory or is it a file. I also want us to take a look at getcwd.
00:37CWD stands for Current Working Directory and it's a little bit like the file pointer
00:43that we have inside of a file as we're moving around in there.
00:46It keeps track of what directory we're in. Now up until now, we have been just working
00:51with everything from absolute references. Every time we tell it what directory
00:54we're talking about, we give it the full path name. But we also have the
00:57ability to move around in the directory structure from this script.
01:02So while file_directories.php is running, we'll have the abilities to change into
01:06a different directory, do some things, change to a different directory and
01:10do some more things there, so that we don't necessarily have to specify
01:14the full file path every time.
01:15Let's go ahead and bring this up and see our current working directory and then
01:19in a moment, we'll actually create a new directory and we can practice moving
01:22into there. So file_directories and you see that it's just the current
01:26directory where file_directories.php is located. That is the current working
01:30directory. So let's try creating a directory. We do that with mkdir, short
01:36for Make Directory. So we can do mkdir and then we'll need to tell it the
01:42name of the directory. We'll call it new and then we also need to tell it what
01:45permissions the directory should have. I'm going to say "0777" and that will
01:50tell it to make that directory sort of wide open for reading and writing and
01:54everything. And I'll also just make a note here that is the PHP default.
01:59Now let's go ahead and try it and let's take a look, let's run our script
02:03again. So, now if we come over here, you can take a look. Here's our folder, new,
02:08and if we actually go to our command line cd Sites/btb_sandbox >ls-la,
02:18it will give us a list of all of them and we can see new. Now notice what happened here.
02:22It did not give it the permissions 777. So you are thinking, wait a minute,
02:28did I give you bad information? Did that not work right?
02:31Well, the reason why is that there's something called umask and it is a mask that is
02:35applied to these permissions whenever a folder is created. And every system has
02:40it's own default umask that is set by default. It's set to be 0022,
02:46I believe, which means that it's going to subtract out 022 from that 777, thus
02:53giving us 755. I'll just go ahead and make it here, default maybe 0022. So this
03:02umask gets applied. We can have the ability to use the umask function to
03:06change it. I'm not going to go into details on how to do that. You can also
03:09just use Chmod, which we learned earlier to change the permissions on this, but
03:13I wanted you to understand umask so that it doesn't stay a mystery to you, as
03:17to why when you tell it, hey, create this with 777, it comes up with 755 for
03:23the permissions instead. I just wanted that to sort of be demystified so that
03:27you know how to change it if you need to.
03:30Now the other thing that we can do is we can create directories recursively,
03:33recursive dir creation, and we can do that with mkdir and I'm going to say
03:45('new/test/test2', 0777, true) and true is for recursive or not. So this will
03:52create not only new but go ahead and create test and test2, everything that it
03:57needs to create all of those, all the way down the line. So if we're passing in
04:01more than just one, you will want to also include that true statement there. So
04:06let's just try this real quick. I could go ahead and hide that or run to start
04:09script again. So file exist on line 11, you will see we got an error here for
04:16this make directory. So you can see that this does check whether it exist or
04:19not. So if we were using this in a real script, we would also want to check and
04:22make sure that this doesn't already exist before we tried to do the mkdir.
04:26But for our purposes, just to learn how this works, we already know how file
04:30exist works. We saw that at the beginning of the file chapter.
04:33So for now, we can just go ahead and say mkdir and we'll just accept those
04:36errors. So let's take a look here inside new, there's test and there's test2.
04:41So that's really all that is to it.
04:43Now let's try changing directories and we can do that with chdir. So,
04:46chdir('new'). That will change into the new directory and now if we say tell us
04:53the working directory, we'll see what we get back there. Now we're going to get
04:56a couple of errors here because those directories already exist. That's all
04:59right. But you will see that now, our working directory is new. So at the
05:03beginning of our script, we had created a new file and opened the file for
05:06writing, it would have been in the btb_ sandbox folder. If we do our chdir and
05:11we move our working directory into new, now when we create a new file it's
05:15going to be in the new folder. Because that's our working directory. It works a
05:19lot like a pointer.
05:20Then of course, the very last thing that we want to learn how to do is to
05:22remove a directory and rmdir, so it is like mkdir for make directory, it's 'rm'
05:27for remove the directory and then we'll need to tell it what the directory is.
05:31Now again, we'll want to make sure that the directory exist before we try and
05:35remove it, we know how to do that, I'm not going to do it here. Now also notice
05:39that I moved my working directory here. I'm inside new, so this won't work.
05:44Let's try it just to see what happens, let's do Reload and you will see that I
05:49come back here with another error saying 'No such file or directory' inside the
05:53folder that's in now, so it's the current working directory. If I take away the
05:56news since I have changed my working directory. Now we come back and I don't
06:00get the warning and if you take a look here, you will see that test2 is now
06:04gone, test still stays there, it just removed the directory at the end of that.
06:08The very last thing that I just want to mention to you is that in order to
06:10remove a directory, that it must be closed and empty before you can remove them
06:15and there are some scripts that can help you figure out how to wipe out all
06:19directories that already have files by looking on the PHP website for rmdir,
06:24you can just search for it, but that will give you scripts that other people
06:27have written, they will help you to recursively delete everything that's in an
06:31entire directory.
06:32Now you know how to create and delete directories and how to move around in
06:36them, we're ready to look at the contents that are in those directories because
06:39a lot of times what we want to do is find out, hey! What files are actually in
06:42this directory? we'll do that in the next movie.
Collapse this transcript
Viewing directory content
00:00In the last movie, we saw how to create and move around in directories.
00:03Now let's see how to actually view the contents of those directories, the files or
00:07other directories that are contained inside.
00:09So for this movie, let's start out by creating a new file again and we'll save
00:12it as file_dircontents.php and we'll create our php tags. The idea of working
00:24with a directory and reading from a directory is very similar to what we did
00:27with working with a file. It's a lot like fopen, fread, and fclose.
00:31We have opendir, readdir and closedir. So the one thing that you want to do is make sure of
00:37course before you start trying to read from something, that it exists and that
00:41is a directory. So here is a standard example of the process we would go
00:44through to output the contents of the directory. I'm going to have a directory,
00:48which I'm just going to use the current directory that I'm in right now.
00:51I'm just using the dot to signify that that's my current working directory. We also
00:55saw how to use getcwd to get the same information. Then I'm going to check and see
00:59is it a directory? If it is a directory, then we're going to use opendir
01:04and we'll get a directory handle, the same way that we got a file handle back.
01:08If we got that successfully, then while we're able to still get something back,
01:14while read directory returns something. So read directory will return the next item.
01:19So there's a pointer that moves through here, it works a lot like the
01:22fgets did, when we were getting each line one by one. Well, this is getting each
01:26item in the directory, one by one and as long as it returns a filename,
01:29then it will keep looping and then we can do whatever we want with that filename.
01:33We can open up that file and look at it, inspect it, change its permissions.
01:37We're inside a loop here. I'm just going to simply going to have it output the filename.
01:40Now notice the filename, not the file handle. We would have to open the file
01:44if we want to have a file handle.
01:45So let's go ahead and just try that for now. Of course, the very last thing
01:49we'll want to make sure that we add after the loop is completely done is to
01:53close the directory. So if we're able to open it, then also let's make sure
01:57that we close it at the end. So let's open up Firefox and we'll look at
02:01file_dircontents, and there we go, we get a list of all of the files. Now,
02:07the file name is something I'm outputting that's here, filename:, and then the file name.
02:12So this lists all the files that are in that directory. Pretty neat, huh?
02:16Now, notice that it included dot, which is the current directory, and dot-dot, which is the
02:21directory one back from here, as well as .DS_Store, which is a private file,
02:26a file that normally doesn't show up. If I come here to the Terminal window,
02:30you can see those files are here as well. So the default listing for a directory is
02:35that it includes private files, it has a listing for itself and it has a
02:39listing for its parent directory as well. Now if we want to hide those, that's
02:44a simple matter for us. We just put an if-then statement, let's say, before
02:47we do this part of the loop. If the file name is a dot, then don't do anything or
02:53if it's dot-dot don't do anything and so on.
02:55So it's a simple matter of leaving those out if we want. But by default,
02:59those will also be in there. Now, I also want to point out that because
03:03it's a pointer that is moving through this file as we do each of these read
03:07directories, we're moving down to the next one. If we get to the end or at any point
03:11we want to rewind and go back to the beginning, we have rewinddir,
03:15which allows us to jump back to the top of the file. So we could loop through the whole file,
03:19then we could rewind and loop through it again if we wanted, maybe
03:23we're doing table or something and we need to one whole column and then rewind to do
03:28another whole column and so on. rewinddir would let us do that.
03:31It does have to happen, of course, before closedir because we need this
03:34directory handle. Once it's closed, the handle goes away.
03:37There is another way that we can do the same thing and that is using scandir
03:44and what it does is it takes all of those filenames and puts them in an array.
03:47And then it's up to us if want to take the array and go through and output it,
03:53which is what I have done here. You can see here that I have put in a little
03:56bit of code that will leave out those files that have a dot at the beginning of them.
03:59So this is essentially the same thing as if we had gone through this loop up here
04:04but instead of outputting it, we'll put each item into an array and built
04:08an array. Scan directory does that for us; it's a shortcut. Now,
04:12it's not a whole lot shorter but it does make things like sorting and doing reverse order
04:16much easier. So if we wanted to do our directory in revere order, we could read
04:20it all into an array, sort the array and then output it in the order that we want.
04:25So that's where that's going to come in really useful. Let's try that out real quick.
04:27So I just did a Refresh. Now it's doing the list twice here.
04:31Let me put in-- I think it will be a little easier to see echo "<hr />".
04:37There we are. Now we'll see when the one list stops and then one starts; you will see that the
04:41dot-dot files are gone now so it starts right here at the access_modifiers.
04:45So that's done by this simple if-then statement here. I'm just searching for the
04:49position of that string in there to see whether or not it occurs at the zero
04:53position or not.
04:54So that's really all there is to working with directories. We have the ability
04:57to create directory, we have the ability to change directories and move around,
05:01we have the ability to see the contents of the directory. And then once
05:04we're able to pull in the contents, we can do things with it inside this loop here so
05:08that we can reach in the file, grab a bit of data, go to the next file, grab a bit of data
05:14and so on and we know how then to delete the directories when we're done with it.
05:17So I think the combination of working with both files and
05:19directories is going to be really powerful. In the next movie, I'm going to
05:22give you an assignment so that you can put all of this knowledge together and
05:26actually try it for yourself.
Collapse this transcript
Creating a log file: Assignment
00:00Now that we understand the theory of how to work with files and directories,
00:03it's time to put it into practical use and the way we're going to that is by
00:07switching back to our photo_gallery project. Remember we have been working in
00:10the btb_sandbox. And in our photo_gallery project, we're going to create a log file.
00:15Whenever an action takes place, we'll have the ability to call a function that
00:18will log a message to a simple text file and then via PHP, we'll be able to
00:23read back in the results of that log file as well. So we'll be able to have
00:28a simple text file that has recorded actions.
00:30Now these could be errors or something like that. In this case, we're going to
00:34be just working on logging when a user logs in. So every time a user logs in,
00:38we'll have a time and date that that user logged in to our log file.
00:41In this video, I'm going over the requirements for this assignment and some of
00:44the steps that you are going to want to follow, but it's going to be up to you
00:47to go off on your own and do it and to apply everything that you have learned
00:50to make this happen and that's really where I think a lot of learning is going
00:53to take place. So, you want to make sure that you do this and then I'll show you
00:56my solution afterwards.
00:58The first step is going to be set up a log directory. So it's going to be
01:01in photo_gallery/logs. Now I believe we created that file earlier. You want to
01:06make sure that it does exists and if it already exists, you will also want to
01:09make sure that the web server is set as the owner. Remember we talked about how
01:13the PHP scripts are not going to be able to make changes to directories that
01:18they don't own.
01:19So we'll want to make sure that that's the case and you will probably have to
01:22do that outside of PHP and we have saw to do that earlier, but just to remind
01:26you that from the command line, sudo chown www, if that's the name of your web
01:31server and then the location of the file and if you are in that directory,
01:35it's just logs. Otherwise you might have to specify more of the paths to find that
01:39file but that will get the log directory setup where we're ready to start
01:43creating files in it.
01:44Once you have your log directory setup, then we're ready to start looking at
01:47the requirements that you are going to need for this exercise.
01:50The first is that we're going to need to code the log action and we're going to
01:54do that in functions.php and the function will be called log_action and we'll
01:58give to two parameters: the action that we want to log and then a message to go
02:02with it. So you want to write that PHP code to make that happen. So inside
02:07there, you are going to want to make sure that the file exists and if it
02:09doesn't, you are going to want to create a new file.
02:11You are going to also want to make sure that the file is writable and if not,
02:14then output an error and when we add these entries, our log entries,
02:19we're going to want to append them to the end of the file and there is a couple of
02:22different ways you can do that. We saw an Append method earlier. We also saw
02:25how we could move the pointer around to write at the end of the file. So
02:29I'll let you choose which one of those you want to try. The entries go ahead and
02:33format like I have got there in the middle of the slide.
02:35Basically, put the date and time and then the action. In this case, Login and
02:39then the message. In this case, it's kskoglund logged in. That's the username
02:43you will have when the person logs in and remember to make use of the constants
02:47we set up, SITE_ROOT and DS for the directory separator and you want to
02:51consider how to handle new lines because at the end of each line, of course,
02:54you will want to go to a new line and remember that double quotes do matter for
02:58using those special characters like \n and \r.
03:02If you use single quotes, it will just interpret them as being literal \n and \r
03:05in order to be a new line character, you need to use double quotes.
03:09Once you have done all that, you have got the log action coded, try using it.
03:13Put it into admin/login.php and see if you can actually log something to the file.
03:19Then you go into the log file, take a look and see if it's there. If not, wipe it out.
03:23Try again until you get it right.
03:25Now in a lot of instances, it might be fine to just have that log file sitting
03:28there. We could open it with the text editor whenever we want to see it.
03:31We're also going to let our application read it in because we know how to do that too.
03:34So the next step in our exercise will be to read back in the log file from a
03:38PHP page. Just like all the other Admin pages, we're going to first confirm
03:42that the user is logged in already because this is not something that
03:45non-logged in people should be able to do and we're going to then locate that
03:48log file and we're going to make sure we use SITE_ROOT and DS, the directory
03:52separator again. We're going to check if the file exists or not, check if its
03:55readable or not and then if its readable, read its contents in and we saw a
03:59couple of way to do that, I'll let you choose on how to do it and then output
04:02those entries to HTML so that we can view them in the browser and there are
04:06several ways that you can output those. We saw nl2br for new line to <br> tag,
04:12you can use that or you can use cascading Style Sheets or an HTML table or
04:17something like that, but the overall ideas that we want to have all those
04:20entries show up in our HTML page.
04:23Once you have got those two parts together, I want you to round out the
04:26functionality of this log file by creating a way for us to clear the log file
04:29out and so in that logfile.php, where we're viewing the file, we're also going
04:34to add a link that just says "Clear the log file" and it's going to request to
04:37URL "logfile.php?clear=true" and then at the top of that same file,
04:43before we display the results of the file, we'll say well, check and see.
04:46if($_Get['clear']=='true'), then clear the logs and then after you have cleared them,
04:52we'll want to make another log entry that let's us know that the log was cleared.
04:56So you want to clear it out and put one entry in there letting you know that
05:00the logs were cleared. Now that's the end of your assignment that you need to
05:03go off and work on and in the next movie, I'll show you the solution.
05:06You can peek at the solution if you run into problems, but even better would be for
05:09you to go back to the movies where we originally discussed those topics and see how
05:13to do it there and then apply it and see if you can get it working and as extra
05:17credit, if you get all of that working and you want to try something else,
05:20try creating a Logger class.
05:21We have talked about classes, we have talked about files. We're going to now
05:25have seen how to work with the log file. You have everything you need to go
05:28ahead and bundle all of this information together into a Logger class that
05:32we could then potentially use in all of our applications going forward.
05:35I'm not going to show you the solution to that but that's just an extra exercise
05:39if you want to try it on your own.
05:40So give it a shot and in the next movie, I'll show you my solutions.
Collapse this transcript
Creating a log file: Solution
00:00In this movie, I'm going to show you the solution that I came up with to the
00:03Create a Log File assignment. Now if you haven't completed that assignment yet,
00:06I encourage you to try it on your own first. It's one of the best ways you are
00:09going to learn how to put all of these pieces together and then once you have,
00:13you can review my solution and see how close we are. They may not be exact and
00:16that's okay. There are a lot of different ways that you can approach these problems,
00:19but I'll show you mine.
00:20So the first requirement of the assignment was to make sure that we had a logs
00:24directory and to make sure that it was available to the web server.
00:28In this case, I made sure that the web server actually owns that file. www is my web
00:33server. Yours might be something else.
00:35The other way to approach, it would be to set the permissions on that file to
00:38something different. Mine are set so that the owner has read and write
00:41privileges to it. Other people just have read privileges. We could change those
00:46and if it wasn't the owner, then we certainly would need to make everyone,
00:49for example, be also read and write, but once we have the log file setup then
00:53we're all set to move on to the second requirement.
00:56The second requirement was for us to code this log action inside functions.php
01:01and you will see that the first thing I did was I had figured out where that
01:04log file ought to be, even though it doesn't necessarily exist yet, where will
01:08it be and I used SITE_ ROOT and DS to say well. It's in the logs directory and
01:12it will be called log.txt.
01:14Now, the way I decided to write the file was using Append. Now Append, one of
01:21its features is that if the file does not already exist, it will create it for
01:26you. If it does exist, it will just grab it, open it up and start appending at
01:30the end. Well that's nice because it actually saves me from having to check
01:33whether the file exists or not. I went ahead and did a File Exist check here
01:38and said well, let's check and see if it's new. And the reason why it is
01:41because once I'm done with all my writing, I just set it to do a Chmod at the
01:45end to say well, make sure that the log file is 0755.
01:49Now that's an optional step, you don't have to do those two steps. I went ahead
01:52and did it. Append has that functionality built-in already where it will either
01:57create a new one or append at the end of the old one. So I open it up in Append mode,
02:01so I'm all set. The pointer's at the end of the file ready to write.
02:05I went ahead and figured out what my time stamp would be using the strftime
02:08function, using just PHP's time. We saw how to do that earlier and then I
02:14assembled the content that I wanted to output altogether into a variable and I
02:18said we're going to put the time stamp, then a pipe, one of the upright bars,
02:22the action, colon and then the message and then new line at the end.
02:27Notice that \n and that's in double quotes. Double quotes are important because
02:33we're using the special character and then I write that content to the file,
02:37close the file and we're all set.
02:38Now of course, if it wouldn't open up for some reason, then we say just a
02:42simple error message "could not open it up." So that's all there is to writing
02:46the log action and now we can call that action whenever we want and here
02:51we'll do that in our login.php. We just simply say log_action and then Login.
02:56We'll call and then what are we going to pass in? We'll pass in the username and
03:00the logged in as the message and that's all there is to it.
03:03Now we can log things to log file that easily. So that takes care of the second
03:06part of the assignment that I gave you, which was to write that log action and
03:09use it and then the next thing we want to do is be able to read that log file
03:13back in. I went ahead and said, where we should be able to find the log file?
03:17Now since we would have this in both places potentially. This could be
03:20something that we would setup in our config so that we could look in our
03:23configuration and know where the log file is instead of having to repeat it
03:27several times throughout our code, but for now, this will do.
03:29Now we'll come back to the GET['clear'] part that was the fourth part of the
03:33assignment. The third part is to read in that log file. So we know where the
03:36log file is. So down here in the HTML, I have got a bit of PHP that's going to
03:40check to see does the file exists, is it readable and can we open it? So if all
03:46three of those things will turn true, then great, we can keep going.
03:50We're ready to read in the file. But if it doesn't exist or if it's not readable or
03:53if we have a problem opening it for any reason, we'll go down here to the else
03:58statement, "Could not read from the {$logfile}."
04:00Now let's assume that it works, in most cases it should. I decided to do it
04:05with some CSS. So I went ahead and had a <ul> just for an unordered list and
04:10then each of the items I decided it would be li's. So there will be a nice HTML
04:14list that we can potentially style them with Style Sheets.
04:17So here is the important part though, I do the loop until we get to the end of
04:21the file, while not equal to the end of the file, get each line and I decided
04:25to use fgets. You could have used fread or something. That would have been
04:28fine. The reason fgets works so well is because we know that each line in the
04:33log file has a new line return after it. We don't necessarily know how long it
04:36is but we know that there is a new line. So fgets handles that for us. It says,
04:41get the next bit of information until you get to a new line.
04:44So for line-by-line files, fgets is the best way to go. And then I went ahead
04:49and added a little bit of text here, an If statement before I actually output
04:53the entry. The reason I decided to do that was that this makes sure that there
04:57is not a new line return without something else there and I discovered that I
05:01needed that one. I started clearing the log file. Sometimes I would have an
05:05extra new line return and I was getting an <li> tag with nothing in it and I
05:10said well, it would be a nice improvement here if I simply just trimmed any
05:13white space from entry. And if there is something there besides just nothing
05:17after we have trimmed away the white space, then output the entry.
05:21That's optional.
05:23Then the fourth part of this assignment was this clearing the log file,
05:27so I pretty much gave you what the link tag should be to make that happen. The part
05:31that you really need to code is up here, if($_GET['clear'] == 'true'). Let me
05:36just expand this and you will see file_ put _contents is what I decided to use
05:42and I told the log file put the contents nothing in that file.
05:47So I wanted to use file_put_contents here, so you could see a place where it's
05:50really useful. Remember this a shorthand way that we can write to the file. Now,
05:54it could have also opened up the file using Overwrite and written in the file
05:58logs cleared. I decided to go ahead and deal with this one line, clear out the
06:02log file by putting nothing in it and then add in that first log entry saying
06:07that the logs were cleared and finally, I said redirect_to. You will see when
06:11that in just a second we try this out, it will redirect to the same page that
06:15the URL wont have "clear=true" anymore in it.
06:18We will see that in action, let's take a look. So I'll go and open up a new
06:21Firefox window and we'll go to localhost /photo_gallery/public and then where I
06:26want to go is actually in to admin/login .php and we'll try that out. I'm going
06:32to login as kskoglund with secretpwd. That was my password, secretpwd. Now I'm
06:41logged in, it should have logged that. Let's take a look at our log file, View
06:45Log File and sure enough here we are, we have got some old logs there, we have
06:49got the new entry that I just created and if I click Create log file, it then
06:53clears up the logs and we start over again.
06:55Now I wanted to show you what I mean by that last redirect here. Let's take
06:59that out for a second and let's just reload the page Log file, okay and let's
07:05clear the log file.
07:06Now because I didn't redirect, notice here that "clear=true". That might cause
07:12us to inadvertently clear the log file again. So by redirecting instead, I make
07:17sure that I clear out that parameter that was sent so that now, once we have
07:22cleared it, it's gone and it has to actually click the link in order to get
07:26that clearing effect again. So while that wasn't part of the assignment, that
07:29is just a good practice to be in, to keep track of what is up in that URL
07:33string because that is something that the User could reload the page, they
07:37could bookmark it, so if you don't want something sort of dangerous or
07:41destructive up in there, you want to make sure that you don't leave it up in there.
07:44So hopefully, you got the same results and you got it working, if not go back,
07:47rewind the movie, see what I did, try it on your own till you get it right.
07:51When you are ready, I'll meet you in the next chapter, where we'll talk about
07:53uploading files via a web form.
Collapse this transcript
8. Uploading Files
Configuring PHP for file uploads
00:00So far in our discussion of files and directories, we have seen how to work
00:04with files and directories that are on the web server already. What we haven't
00:07seen is how we can upload files from a client's web browser to our web server.
00:12Keep in mind, when we're developing, they are on the same place but when we're done,
00:16we may actually deploy our photo gallery application to a web hosting
00:20service that might be in Kansas City. Meanwhile, we might be in San Francisco
00:25or Miami and be uploading files to that server using a web interface and that's
00:30what we want to learn how to do in this chapter is how to upload files to PHP.
00:34Before we can do that though, we need to take a look at how we need to
00:37configure PHP so that it's able to do file uploads. In php.ini, there are a
00:42number of different options that we can set and configure. Probably,
00:46by default, all of these are going to be set correctly on your machine, but every
00:50distribution is different, so you want to bring up php.ini or take a look at
00:54php.info, remember how we did that script, we'll look at that in a second and
00:58you will want to examine these options and make sure they are set to the right thing.
01:02The first and the most important, which is file_uploads turned On. It's
01:06possible to turn it Off so that PHP won't accept file uploads, so it should
01:10have to be On or possibly it's true or 1, those all accomplish the same thing
01:14and then upload_tmp_dir is where we're going to upload files temporarily. We
01:20just need a place where we can put them when they are being uploaded and we can
01:23grab them out of there and work with them afterwards. So that's going to be the
01:26temp directory. Null is the default or it might just be simply not defined at
01:30all on your machine, in which case it will use the system's temp directory and
01:35in most cases that's fine as long as you have access to that, as long as the
01:38web server has access to it, as long as it has read and write abilities that we
01:42have talked about before, otherwise you can assign a different upload_tmp_dir
01:46and then the remaining five options all have to do with the size of the file
01:50that you are going to allowed to be uploaded and how long you are going to let
01:53PHP spend trying to actually accomplish that task, how long it's going to wait
01:58to get that file and receive it over the internet.
02:00So on a slow connection, you might need a little bit more time. So typically
02:04these options work pretty well. The maximum size for any post-request is 8M.
02:10The upload_max_filesize is set by default at 2M. Now you can change those and
02:15configure them and make it 3, 4, whatever you want, but by default, that's the
02:19maximum size.
02:20If you are trying to upload a 3M file and it's not working and you are beating
02:24your head against the wall going, wait a minute, my PHP has got to be right.
02:27Well, it may be that you never set this upload max file size to allow files
02:31that large to be received. So you want to take a look at that and just know at
02:35least what's there. Even if you don't change it, you want to know how you have
02:38it configured. And then the execution time is how long it should spend
02:42executing. Input time is how long it will spend processing, which is slightly
02:46different. By default it's set to no limit and that's so the recommended thing.
02:50Then memory_limit, how much memory is each script allowed to use and 128M is
02:56probably the default. You can up it if you find that you need more memory. So
02:59even though these are all probably configured correctly for you already, it's
03:03worth knowing what they are and more importantly, it's worth knowing where
03:07they are and that they may need changing in case you have to troubleshoot your PHP uploads.
03:12Let's take a look at the pho.info file just to see some of these settings. So,
03:17here I'm in my btb_sandbox. We have created this file earlier, my_phpinfo.
03:21That will just run that php_info function and allows us to see everything that's
03:26setup and if we just do a couple of finds here, I'll just do find for
03:31file_upload and here it is file_uploads is set to On for me. I can do another one.
03:37Let's do upload_temp_dir, no value, so that means it's going to use the
03:44default directory. That's the same as being Null. Then let's say post_max_size.
03:50There we are. You see that 8M and you can keep going through all of them and
03:55just take a look, see what they are all set to. Mine are all set to those
03:58defaults. If yours aren't, you can try it with what you have got or you can
04:02adjust yours accordingly, but those are sort of the key parameters we need to work with.
04:06Now the last bit of housekeeping I want us to do before we actually start
04:09diving into the PHP code is to create the Upload folder where we're going to
04:13input all of these files that we're uploading and we're going to move back to
04:16our btb_sandbox, so that's where we are. We're in btb_sandbox, not in the
04:19photo_gallery and we're going to create an upload here and then we'll learn how
04:23to apply it to our photo_gallery, just like we have been doing.
04:26So the first thing we're going to need is a new directory here, you can create
04:29the directory however you like, I'll just go to the File menu and I'll click
04:33New Folder for me and we're going to call it uploads and that's where we're
04:40going to do our uploads to.
04:42Now of course, we know from working with files already that the important thing
04:46here is that we navigate into that directory, btb_sandbox and we take a look
04:54ls-la and we take a look at uploads to see who owns it and what permissions do
05:00they have. Well, right now I own it, so we're going to need to also do sudo
05:04chown and then whatever your web server is, mine is www.uploads and it's going
05:11to want my password. I can remember it on here. There we are. And if you really
05:15want to open that up to everyone, remember that we can do Chmod and we can do
05:20777 uploads and that will then change it so that everyone has the ability to
05:27read and write into that folder.
05:28Now that may not be a good thing on a web server, but since this is a temporary
05:31directory we're just playing around, that's perfectly fine. So make sure that
05:35you have read and write access into that directory and then in the next movie,
05:38we'll start seeing how to send files as form data.
Collapse this transcript
Sending files as form data
00:00Now that we know what are the trouble spots in configuring PHP and we have a
00:03directory for our file uploads, we're ready to actually put those on to an HTML form
00:07or in other words, how to send the file as part of the form data, our post request.
00:13So to get us started, I'm actually going to jump up here to the basic.html that
00:17we created a long time ago and I'm just going to make it File > Save As and that
00:23will give us some HTML to start with. I'm going to call it upload.php and
00:27I'll save it in the btb_sandbox and then let's just call it Upload.
00:31Now you are familiar with basic HTML web forms. This will be an example of a
00:35very simple web form that would be a post request. It would post back to
00:39itself, upload.php. It would send some variables in the inputs as well as the
00:45Submit button and then what we would typically do is up at the top, we would
00:49have some PHP that would actually do the form processing before it got to the form.
00:54So now what I'm going to show you is how we can modify that so that it will
00:56work with file uploading. Now the first important thing that we need to add is
01:02enctype="multipart/form-data", so that lets it know that that's what it's going
01:12to be sending as multipart form-data. Essentially, it says there will not only
01:17be text here, there may be files also. That's what that's telling it.
01:22It's an essential part of HTML, not PHP. HTML that we put that in whenever we're going
01:27to send a file in our post-request. Then the second thing is the input type
01:32that we use for files is file and then the name of the file, which I'll call
01:37file_upload, that's going to give us a nice button that will let us select the
01:41file that we would like to upload.
01:42Now that's all just HTML, there is no PHP there. Let's go ahead and just save
01:46that real quick and let's open up a web browser and instead of being in the
01:51photo_gallery, let me just back up here and go to the sandbox to upload.php.
02:00So here we are. It's just a real simple web form and you will see when I click in it,
02:03it says okay, you are ready to upload. Browse, it let's me browse and then
02:08Upload is the button that will actually let me upload that file. So that's what
02:12we have got in our HTML.
02:13So the most important part there is just that we have this ink type file
02:17form-data and then we us type-file. There is one other important thing that
02:21we want to add when we're working with PHP and that is a declaration of the type
02:26'hidden' for "MAX_FILE_SIZE", all Caps, MAX_FILE_SIZE and then a value in bytes
02:35for how large the maximum file size can be.
02:38Now I'm going to go ahead and just paste in a comment here in PHP that will
02:42give you a reminder. Let's take a look at that. I need to just move this over a bit,
02:47there we are. The maximum file size in bytes must be declared before that
02:51file input field and it can't be larger than the setting in our
02:55upload_max_filesize that's in php.ini. So we don't want to go any larger than that.
03:00That's going to always be the ultimate authority for what the
03:03maximum_filesize_php will allow. It's going to be what's in that file.
03:07Now, this form value can be manipulated and you should still use it, it's a good practice,
03:11but you are going to rely on that upload_max_filesize to make sure
03:15that nothing larger than that ever comes through, but what we're saying is
03:19for this form, this is the maximum. Now someone can hack that, so it's not 100%
03:24reliable, but you can think of it as a polite declaration, a way of saying to PHP,
03:28here comes the file that is less than this size and if it turns out that's not true,
03:32PHP will stop and complain.
03:35So it's a nice way of saying, hey PHP, someone gave you a file and here is what
03:39to expect. Now I went ahead and just put in 10000000 here as the value, so
03:4310000000 bytes would be roughly 1M. Now that's not exactly 1M, if precision
03:48matters, you could put in the actual value there and that's really all there is
03:52to making this work with PHP. That's all there is for us to be able to upload a file
03:56and the very last thing that I'll do here is just to put in a little PHP
04:00that will allow us to pass some messages from the form processing that will be
04:04up here at the top, down to the bottom so that we can say, hey, your file was
04:08uploaded successfully or hey, there was a problem.
04:10We will go ahead and take care of that now so that we can pass those messages.
04:14Now in the next movie, we'll take a look at how we can inspect the file that
04:17gets uploaded by this form when we actually post the form. Let's see that in the next movie.
Collapse this transcript
Inspecting uploaded files
00:00Now that we have a web form that can submit files for uploading, we now need to
00:04learn how to process those files and the first step is going to be to
00:07understand what's being submitted and to inspect the uploaded files that comes across.
00:13In order to do that, we're going to need to look at another super global.
00:16We looked at a bunch of them already. We saw Get, Post, Cookie, Session and
00:19Server, but there is one more which is called Files, and Files is going to
00:23contain any uploaded files submitted with the Post Request.
00:27So it's not going to be found in the Post super global. Files will get split
00:30off and they will get pushed into the File super global separately. All of our
00:34other Post variables will still be in Post. Just Files will be in Files.
00:39The way we're going to access those is to say, well, what is the name of that
00:42form input field? In our case, it was file_upload and $_FILES, and then in
00:47square brackets, and then the name of the field that was submitted will give us
00:52back an associative array and that array is going to contain five pieces of data.
00:56It's going to have the name of the file, its original file name on the user's machine.
01:01It's going to have the type of file that it was, the mime type that
01:04get sent when it's sent by the browser, the size and bytes of the file,
01:08the temporary name where the file was stored on the server, and the error code that goes with it.
01:13We'll take a look at errors in the next movie, for now let's focus on the other four.
01:16The example at the bottom that will show the syntax of how we're going to
01:19pull back a single one of those items. file_upload name would then be the
01:24original file name, and we can make use of that. We can change it or we can
01:27keep the same name, it's up to us. But that's where we'll get that value.
01:31One great way for you to see this array and what it looks like is to just try
01:35it out. So we have our form for our form processing. Instead of actually doing
01:39any real form processing at this point, let's just output something.
01:43We are just going to put in pre tags. That's going to basically respect the
01:46white space formatting, the HTML thing and even though we're not inside the
01:50HTML, we could drop this down here inside the body. For now, we're just going
01:53to put it up here at the top. It's not perfectly valid HTML but that's okay.
01:57Pre tags, print_r, which will print out the array for us, it's there and then
02:03file_upload, and then we'll put an hr tag at the end. So let's just try this
02:07out and see what we get back.
02:09So if I open up Firefox, here I'm with upload.php. I'll just reload the page.
02:14You will see I get my hr tag, Browse, and I'll just go into btb_sandbox for now
02:19and I'll go and just find filetest.txt. That was the file we were practising,
02:26writing to earlier. I'm going to send that. And you will see I put the whole
02:30path here, for where that file is located. And when I click Upload, it's going
02:34to send that file right away.
02:36Now notice here it's not an image file. This is not unique to sending images.
02:40It's any kind of file we want. It can be a text file, Excel file, Word
02:44document, any file gets sent the same way.
02:47So where we click Upload and look what we get back. We get the same form again
02:51but our output at the top says here is the contents of that array.
02:55The file name is filetest.txt. No path or anything, just the file name.
03:00The type, text/plain.
03:02If it had been an image, it might have said that it was a JPEG, for example.
03:06The tmp_name, this is where the file is stored. Notice that that's a full path.
03:10For me, that being stored in the system's default temp directory, which is
03:13/private/var/tmp, yours is very possibly in a different location.
03:18But notice that the name of the file is something crazy that it came up with,
03:22phpWH6foz. That's where the file is on my server. I need to get that tmp_name,
03:28if I want to look at that file, if I want to move that file, or do anything
03:32with it. I'm going to need to reference that item in the array to find out the
03:35name of the file. The error you will see is zero, which means that there were
03:38no errors, and the size of the file is 14 bytes. That's all there is to it. So
03:43this demonstrates to you what that array looks like.
03:46Now in the next movie, we'll take a little bit of a closer look at some of the
03:48possible upload errors that you could come across, before we look at moving the
03:53uploaded files and working with those.
Collapse this transcript
Uploading errors
00:00Now in the last movie, we saw how that one of the values inside that file's
00:04super global array is the error code that gets returned. In this movie, I want
00:08to take a little closer look at the possible error codes you can get back and
00:11talk about how to handle them effectively.
00:13First, let's look at the list. There are eight possible errors that we can get back.
00:17Now the first is not actually an error. It's error 0. It means that there
00:20were no errors. So in that case, there is actually seven. If we take a look at
00:24each one of those, in the first column, we have the name of the error, and
00:27in the second column, we have the number of the error.
00:30That's not really a name. The first one is actually a constant. It's a constant
00:34in all capitals that's equal to the value of the number. So we can use either
00:39one for checking. We can say if we get back Upload_err_ok, or if we get back 0,
00:44then take this action. So both of them will work for us. I find it's a little
00:47easier to work with the named ones than it is the numbers, but if you find
00:51that's easier for you the other way around, that's fine.
00:53Then the third column there explains what each of the errors are. So you have
00:57seen the first one. The second one, the ini_size error means that the upload
01:01was larger than what was specified in the PHP INI file. So we could either
01:06increase that or we could return an error saying, hey! Sorry, that file is too large.
01:10Now error number 2 says that the form size was too large, which means that that
01:16max_filesize value we sent, it went over that number. So we get the ability to
01:20check for both. Did it go over our max_ filesize and did it go over the PHP size?
01:27Error number 3 is that there was a partial upload. The file didn't finish.
01:31Error 4 would be that no file was sent at all. You will notice that error
01:35number 5 is missing from the sequence. That's an old error. That's gone now.
01:39Error number 6 though is that there is no temporary directory and number 7 is
01:44that we can't write to the disk. There is a read/write problem, permissions
01:47problem probably.
01:49The last one is a little obscure but it says that there is some kind of an
01:51extension that's stopping the file upload. So we would know to troubleshoot
01:55then our extensions, which is something we haven't talked about yet. You can
01:58also always get a full list of these on the PHP website, and I put the URL down
02:02there where you can look those up.
02:03But what I want to move on to show you now is how we can effectively handle the
02:07errors and give the user some nice messages back. Essentially, what we want to
02:11do is convert the results we get from either column 1 or column 2 into column 3
02:16that we can return as a nice message to the user.
02:19So I found that the best way to do that is to define an array, which is just
02:23going to be called upload_errors, and its associative array that contains those
02:28names that we just saw with a message. Then we have the ability to look up the
02:32error and output the message, find the key, return the value. Note, then it'll
02:37allows me to give something nice back to the user.
02:40We can try that even now without having done anything else by just simply
02:44finding that error inside file_upload error, and then using that as the key or
02:50the index for where we would find the message that it should return. We have
02:54already setup message down here, so it would return the message. Let's try it.
02:58So I'm just going to bring up Firefox and here I'm with upload.php. I'm going
03:04to browse again to that same file we did before, filetest.txt. You can put
03:09anything you want at all, it doesn't matter, and then say Upload. So here we
03:14are, you will see the error it gave was 0 and it came back and returned
03:18"No errors" to us.
03:19Now let's just try this time without browsing for anything at all, or
03:22I'll leave it blank and just hit Upload. You see it came back with error 4 and
03:27the error was "No file". Now we can also try uploading files that we know were too
03:31large or setting some of those maximum values lower, just to see if we can try
03:35and get back all those errors, but I don't think it's really necessary.
03:37We know that it's working now, we know that that feature is working and that's
03:40why I want to show you is that here is a way to gracefully handle those errors
03:44that we give back to the user.
03:46Now we have a better understanding of the error codes. In the next movie, let's
03:49go back to looking at how we can work with those uploaded files, specifically,
03:52how we can move them out of the temporary directory into whatever directory
03:56we want to work with them and keep them in.
Collapse this transcript
Moving uploaded files
00:00A few movies back, we talked about how to upload files via a web form, I noted
00:04that the moment that you hit Submit, it sends the file to the web server, and
00:07at that point the file has been transferred, it's on the web server. It's just
00:12sitting in a temporary directory, waiting for us to do something with it.
00:15Now we can read that file where it is, we can write to it, we can delete it.
00:20It's a perfectly legitimate file just sitting in the temporary directory.
00:24Chances are we don't want to do those things. Chances are we want to move
00:28that file out of the temporary directory, give it a name that we like, and
00:31put it someplace more permanent. After all, the temporary directory could get
00:34overwritten; the system could wipe out those files periodically if it wants to.
00:38That's why it's called a temp directory.
00:40So in this movie, we're going to see how to move those files into our uploads folder.
00:44So I'm back in upload.php, and I'm just going to take out the pretext,
00:48where we're inspecting those values. We don't need to inspect those anymore.
00:52I am just going to put in some basic skeleton for our form processing. We have
00:56seen this kind of thing before. But we're only doing a single page submission,
00:59and the form submits to itself. We're going to check and see, was the post
01:03variable submitted. If it was, then we'll want to process the form data, in
01:07this case, move the file over. We'll be using this error, but not just yet.
01:12If we're going to move the file, the first thing we need to know is what file
01:16do we need to move. So, that's going to be the temporary file, and we saw how
01:19to do that by using temp name before.
01:21The second thing we want to come up with though is that location of where we
01:25want to put the file. So the name of the file can be anything we want.
01:28You could name it, 0123abc.jpg, or you could go to a database, and look at what
01:35the next value is ought to be or something. It could be based on the user's name,
01:38maybe this is user K. Skoglund's headshot, and so we could call it,
01:42kskoglund_headshot. It's your chance to name it whatever you want, but we do
01:46have access to what it was named originally on the user's computer. So in this
01:51case I'm going to use that same name. We're not going to change the name;
01:54we're going to keep the name that they had.
01:56But because I'm keeping their name, I'm going to run it through a function
01:59called, basename. basename is going to make sure that we get just the name of
02:03the file that's at the end. So that's going to be, for example, picture.jpg. It
02:08will be the name of the file dot extension.
02:10What it's also going to do is help ensure that our system doesn't get hacked by
02:14someone putting in something that's a little bit crazy for a name of a file
02:18that might interact with our file system in a bad way. It's going to help sort
02:21of purify it for us or escape it. So basename is going to be good for that, and
02:26that will give us then the target file. Then I'm going to go ahead and say
02:29well, the upload directory where we want to put these is going to be in uploads.
02:33Now there could be a plenty of sort of preprocessing of taking a look at those
02:36values that were there. You could check to see if the file exists first, to
02:39make sure that you are not going to accidentally try to override it or
02:42something like that. You also could stop and do checking here to see whether or
02:46not there were actually any errors in the form as well.
02:49I am not going to any of that. Instead, I'm going to move directly to taking a
02:52look at what we need to move this file. That is going to be move_uploaded_file.
02:59That's the PHP function that will move the file. It only moves files that have
03:04been uploaded, files that are sitting in that temporary directory, and it knows
03:08because it's there, that it's an uploaded file. That can tell.
03:11So what we wanted to say is move the uploaded file, with this name, $tmp_file,
03:18and move it to -- and in this case, we're going to say it's going to be the
03:22$upload_dir, and then dot and then /. We don't have access to DS here.
03:28That's something that is in our other application. So we'll just use the /.
03:32So $upload_dir."/".$target_file. That's where it should go to.
03:37So that's what we want to do; we want to move the file there. Now that will do it on its own.
03:41That PHP function will attempt to move the file.
03:44But let me make a note here, which is that move_uploaded_file will return
03:48false, if the file is not a valid upload file or if it cannot be removed for
03:53any other reason. Well, since it returns false, there is a great reason that we
03:56can put if around it. So if we were able to move the file, then do one thing,
04:04else, do something else. Let's grab this because we know that the else we would
04:09want to do if something goes wrong is display an error there. And if not, let's
04:14put in a simple $message = " File uploaded successfully".
04:22So we wrap it in an if-else statement, but ultimately what we're doing is
04:25saying, were we able to move the uploaded file from its temporary place to the
04:31target place, where we wanted, with the name that we've given it. That's all
04:35there to it. That's absolutely all there is to moving files after they have
04:40been uploaded.
04:40Let's go ahead and try it out. I'll save this. Let's get our directory here
04:44where we can see it. Here is uploads, and uploads right now has nothing in it.
04:49We did make sure earlier that it was writable. So now we would just need to go
04:52to Firefox and let's upload a file. So Browse, and we'll take that same file
04:57again, you could put a different one if you want, filetest.txt, and open it.
05:03Then Upload, "File uploaded successfully". Let's take a look over here, and
05:07sure enough, here it is.
05:09Now it's uploading it to a directory on the same server, but this could be on
05:13two separate servers, so that this is on a local copy, let's say in Chicago,
05:18and this one is on another copy that's in Dallas, and it's uploading it to that
05:21directory. Don't be fooled by the fact that these are in the same place. It's
05:25because we're running both our web browser and the web server in the same place.
05:29That's really all there is to uploading files, once you understand those
05:32configuration options, you make a few changes to your form, then it's simply a
05:36matter of pulling values out of the super globals and using move_uploaded_file
05:40to put the new file in the right place.
05:42I think that you now have a very good understanding of how files and
05:45directories work in PHP, and you should feel very comfortable by now.
05:48We're ready to move back to the Photo Gallery and finish flushing out that application.
Collapse this transcript
9. Completing the User Class
Remaining user CRUD
00:00In the last few chapters we have been working with and uploading files. Once
00:03you know how to work with databases, objects and these uploaded files, then the
00:07next few chapters should be pretty straightforward. Essentially, we would just
00:10be pulling together all of these concepts. But before we can start uploading
00:13files to new photograph class, we need to add a few more object oriented methods first.
00:17We will start by adding these methods to our existing user class. This should
00:20be a very straightforward usage example. Then we can apply those concepts to
00:24our photograph class after that. Now earlier we created the ability to log in
00:29and log out by finding users in our database. But we skipped over the part
00:32about creating, updating and deleting users. The other parts of CRUD, Create,
00:37Read, Update and Delete. So let's add those methods now.
00:40So we're going to be switching from the btb_sandbox back to the photo_gallery.
00:43So open up that photo_gallery directory again, and we're going to be working on
00:46user.php to begin with. So I'm going to open that up. Now if you remember, we
00:51had gone through and created some authentication methods, as well as some
00:55common database methods. We talked about why we wouldn't be able to move those
00:58up to database objects, until we have the ability to do Late Static Bindings,
01:02but for now we have these static methods that we have created.
01:05Well, right below this, we're going to create a few new ones and they are going
01:09to be, create, update and delete. Notice that these aren't Static methods.
01:13These are Public Instance methods. If you think back, our Find methods,
01:17find_all, find_by_id, find_by_sql or Static methods, because we want to be able
01:21to call them from the Class level. They returned instances, but we didn't have
01:25an instance to begin with.
01:26Unlike our Find method, these three methods will all require that we have an
01:29instance of an object to begin with. We want to add or update its attributes in
01:33the database or delete its database entry altogether. In each of those cases
01:37though, we're going to have an object to start with, an object that we want to
01:41save to the database or an object that we want to update in the database.
01:45Now just like those Static methods we created earlier, we might eventually want
01:49to promote these to the database object class, keeping in mind any problems
01:53with early Static Binding. But we'll start out by creating them in the user
01:56class. I think it will be easier to work within there.
01:59So let's start up by focusing on coding the Create method, and we'll do that in
02:02the next movie.
Collapse this transcript
Creating users
00:00In order to complete the user CRUD, we're going to start out by writing the
00:03create method, in order to allow us to create users.
00:06Now the first thing I want to point out to you is that this is different from
00:09simply instantiating a new user. With that, we did something like $user = new
00:14User. What we're talking about now is writing a method that will take that
00:18instance, and allow it to be saved to the database. So we can attach attributes
00:22to it, the first_name, the last_name, the username, the password, and then
00:26we can tell it, all right, save that to the database. We'll do that using a method
00:31that we'll call create.
00:32Now because we're going to be working with the database, the very first thing
00:35we're going to want to do is use global to bring in database. That is the
00:41variable that we had already defined that has an instance of our database
00:45object. So then we can use it to run queries, for example.
00:47Now I'm going to post in some comments here, just to remind you that we don't
00:51want to forget our SQL syntax, and our good SQL habits. So I have gone ahead
00:56and just reminded you sort of what the basic structure of a insert statement
01:00ought to look like, and then made a couple of notes about our good habits that
01:03we're going to put single quotes around all the values, and we're going to
01:06escape all the values, to prevent SQL Injection.
01:10Now keeping those points in mind, we're ready to actually write the SQL. Now
01:13I'm going to go ahead and just paste it in here and let you take a look. We're
01:16going to insert into the table users, and right now I'm going to go ahead and
01:20just say users. I'm not going to try and find that dynamically, even though if
01:24you remember up here at the top, we defined that as table name. For now,
01:28we're just going to go ahead and put it in and hard code it. We can abstract it later
01:32and we'll do that.
01:33Then I have got the field names, so we have got username, password, first_name
01:36and last_name. Those are the fields that we're going to try and update. I left
01:40ID out of there, because ID will autoupdate on its own, because we have set it
01:44to auto increment when we created the database. So I don't need to send a value for that.
01:48Then I have got VALUES, and then notice I've got a single quote here, followed
01:52by the first value, which is going to be username, and I'm using escape value,
01:56that method we wrote in the database class. That will escape things so that
02:00they are safe from MySQL Injection. Then I have got a single quote, comma,
02:05space, and then another single quote.
02:07Now from this single quote down to this single quote is one value. I have just
02:12put the single quote up on the line before it, don't let that pull you or throw
02:15you off. You need to be careful and make sure that you have all these pairings
02:18of single quotes correct. Then I have got commas between all of them and then
02:22I have got the last one here, comma, and then close the parenthesis on VALUES.
02:27So be very careful about your SQL syntax, make sure that you have got it all
02:31right. But when we're done, then we're simply ready to run our query statement.
02:36Running this SQL query is very simple, because we coded our database class and
02:41we have a method called query. So we simply say run this query. If it returns
02:45true, then return true, if not, then it returned false. That will let us know,
02:50whether it happened or not.
02:51Now there is one additional thing that we need to take care of with an insert
02:55statement. This is a very important step. We want to also update the id
03:00attributes of the object to be whatever the database just saved that as. We
03:04don't know what that is because it was auto incrementing, and there could be
03:07several insert statements happening from different users at the same time.
03:11So we want to tell the database class to use its insert_id method to give us
03:15that id value and then we'll put it in this object. So now, we already have the
03:20username, the password, the first name, and the last name stored. Now we also
03:24have the id. So this is all there is to it.
03:26Now we have coded a create action that will take whatever the current
03:30parameters are in this object and will add them to the database. So let's test
03:34this out. I'm going to close up that file, and let's go into, public, admin,
03:39and then I'm going to take the index.php action. I'm just going to do
03:43File>Duplicate on it. I'll have copy, and I'm just going to call it, test, and
03:47this is where I'm just going to do some testing.
03:49I'm going to open this up, and I'll go ahead and leave all the header and
03:53everything in there. I'm just going to take out the HTML that we had. This will
03:56initialize it. It will make sure we're logged in. So testing our new create
04:00method is going to be easy. We just simply instantiate a new user, and then
04:04give it all of the attributes that we want, and then tell it create. Now we
04:09could make this last line into an if- then statement that would perform one set
04:14of actions if it created or not successfully. But I'm just going to actually
04:17look in the database to see if it got created or not.
04:20So before we test this out, I'm just going to open up my phpMyAdmin that I have,
04:25so that I can see what's in the database. It will just make it nice and
04:27easy to see when these records get added. So you can see I have already got the
04:31user that I created earlier. Refreshing it just shows that same user.
04:35Now what I want to do is use that test page. I'll create a new window here and
04:39we'll go to, photo_gallery/public/admin /test.php. I'll need to log in first,
04:50secretpwd, all right, now let's go that test page, test.php, all right. Now,
04:58I don't see anything on the page, but that's because I didn't actually echo
05:01anything back. It should have still made its entry in the database, and
05:05you will see there it is. johnsmith with the password that I gave it.
05:08Now if you have written that create statement, then you should get the same
05:11result, if not, you want to go back and debug it till you get a similar result.
05:15In the next movie, we'll see how to code the update method.
Collapse this transcript
Updating users
00:00In this movie, we'll work on coding that update method inside our user class.
00:04The idea here is that we have already pulled an instance down from the
00:08database. It already exists in the database; we have now made an object
00:11instance of it. We change a few attributes on it and we want to save those
00:15changes to the database. We're going to write a method that will allow us to do that.
00:19Now I'm going to set the test.php aside for now and go back to user.php.
00:24We'll use test again in a minute. I want to focus on coding the update method. So,
00:28just like before, I'm going to bring in the database from the global scope so
00:32that we can use that. Then I'm going to just put a few notes here to remind you
00:37what the SQL syntax should like and then the good SQL habits we want to
00:42make sure that we also keep.
00:44Now the SQL that we're going to write for this is going to look like this.
00:47Let me just expand this so that it all shows up nice and neat. We're going to
00:51update the user's table. We're going to set the key username=, here is a
00:58single quote, the escaped value of username from this object, the attribute
01:03username, and then another single quote. So the escape value will make sure
01:06that we don't have any problems with the SQL injection and then we have got
01:10comma, space, and then the next value.
01:13Notice that there is a space here before the WHERE. The WHERE lets it know
01:17where to locate the record that we want to update, so we definitely need that
01:22condition, telling it which one. And I just want to make sure that there is a
01:25space there. It doesn't matter whether you put it before the WHERE, if you put it here,
01:29but your SQL will be invalid if you don't have a space between this
01:33last single quote and the WHERE statement.
01:35So, id=, and then we go ahead and escape the value of id again. Now that's not
01:40strictly necessary, because the id probably was pulled from the database to
01:44begin with, but it's a good practice. It doesn't hurt just to make sure that
01:49this somehow didn't get changed, so we're go ahead and escape it one more time.
01:53You could also choose to leave that step out.
01:55Now once we have all our SQL constructed, we're ready to run the database query.
02:00And you remember from the Essential Training that the way to know
02:03whether this happened or not is not to see whether it returns true, like we did
02:07for the create action. Let's look at that. If the database query returned true or not.
02:12With update actions, what we want to test is whether the affected_rows
02:16is equal to 1. So if affected_rows equals 1, then return true, otherwise return false.
02:23That will be all that we need for our update action. So I'll close that.
02:27Now in order to test it out, I'll open up test.php and I'll start by just commenting
02:32all of this out, so that we won't recreate the record and instead, we'll say
02:36user= and we'll need to pull the user out of the database. I'll do that using
02:40a static method that we wrote earlier, find_by_id, and the id that I want to find,
02:46I can look in phpMyAdmin and it's id number 2.
02:51So find_by_id number 2. That will pull it out of the database. Now let's make a
02:55change to one of its attributes. Let's say the password is now going to be
02:59equal to, instead of abcd12345, let's just reverse it so it's 12345abcd.
03:09Then last of all, tell it, okay, now that you have made that change, update.
03:14Now we could again, put an if statement here to test whether it happened or not.
03:17We're actually going to look directly into database, because we're not
03:19interested in providing user-friendly messages, as much as we're making sure
03:23that our method is actually working. So I'll save it. I'll go back and
03:27we'll reload the test page. That's now going to run my update code, not my create code.
03:31Okay, now that it has run, let's take a look and let's just refresh the database,
03:36and sure enough, it made the change, 12345abcd.
03:41Now if you didn't get that result, you want to go back and debug it. Make sure
03:43that your SQL is right, until you get the same result. Now I'm going to make
03:47one more improvement here before we go on, which is I'm going to open up user
03:51again. I'll just collapse this down, so that we see create and update.
03:55Now I'm going to write another nice, convenience function here, function save.
04:03Now it would be great if we didn't have to keep track of whether or not
04:06the object was actually in the database or not. We could just say save and figure
04:10out whether or not it had previously been saved or not.
04:13So save would perform both; it would either create it if it needed to be or
04:17it would update it. It turns out that's pretty easy to do because a new record
04:22won't have an id. So if we have id set already, then we know that it is a
04:28record that's from the database. If id has not been set, then we know that this
04:32has not yet been saved in the database. And so, we can have a simple function
04:36called save that will choose whether or not it should run the update method or
04:40whether it should run the create method.
04:42We can try it out and make sure that it works using that test page again.
04:44Let's just go back there real quick, test.php, and this time let's change it to be,
04:50wxyz for the password and instead of update, we'll say save, and then let's go
04:57back to Firefox. We'll reload our test page and we'll check our code, refresh,
05:04and it still works.
05:05Now it not only will save make it a little bit easier on us to write, because
05:09we don't have to remember create and update. We can just use save as the
05:12single method, but it actually prevents mistakes, because the way that we have
05:16written the create method now, we actually could create an object using an
05:20instance and then we could say create again and it would create it again.
05:24It doesn't have any kind of mechanism in there to make sure that this hasn't
05:28already been created.
05:29Now we could write one. We could say well, if it has an id then don't create it,
05:32but it's easier just to write one here and let the object be smart
05:36about which one it ought to perform. Now probably to be safe, you would
05:39actually probably want to make these, instead of being public, you would want
05:42to make them protected, so that you actually could not call create and update
05:47directly. You would have to use save; you would force the user to use save.
05:50But for now, I'll leave them public and leave that choice up to you.
05:53In the next movie, let's take a look at how we can write the delete method.
Collapse this transcript
Deleting users
00:00Now that we have seen how to create and update users, we're going to want to
00:03write the method for allowing us to delete users. Once again we're going to
00:06have an instance that we have already pulled from the database, so it exists in
00:09the database. It's been instantiated and we're going to then have an instance
00:13method called delete that will delete it from the database.
00:16Once you know how to do create and update, I think you will find that delete is
00:19very simple. Now just like before, I'm going to open up user.php and what
00:23we're going to be focused on is the delete method, and just like we did last time,
00:27we're going to call in from the global scope, the database, so that we can use it.
00:31I will put in my comment reminder about some of those good SQL habits, and the
00:36syntax for delete, delete from the table where some condition is met.
00:42Then LIMIT 1, it's always a good practice if we only want to delete a single record
00:47to go ahead and put this sort of extra insurance in there. Now because
00:50we're going to be using id for the condition, there should only be one record with
00:54that id. But it's still a good practice to go ahead and use that LIMIT 1.
00:58So the SQL, I'll go ahead and just paste in so we can take a look at that.
01:02It is just going to be simply "DELETE FROM users", "WHERE id =", and then the id
01:06of this current object, and make sure you have a space again between all of
01:10these different lines, make sure that we have spacing, and then LIMIT 1.
01:15Just like the update, the test of whether the query worked is actually going to be
01:19affected_rows to see whether the rows affected was 1 or not.
01:23So that's all there is to it. Let's just save that and let's open up our
01:26test.php again, and I'm going to comment out the update that we did earlier,
01:31and let's just do a new one. We'll go ahead and find it again, there we go,
01:37find user with the id 2. This time though, we want to say user->delete, and
01:45that should delete our user, should be that simple.
01:47So let's bring out phpMyAdmin, we'll let's just refresh it to make sure that
01:51we've still got johnsmith there, id number 2. Then we'll open up our test page,
01:58we'll run it, and now we come back and we say Refresh, and he is gone. So the
02:04user was deleted successfully.
02:06Now one point that I want to make to you here is that once we performed
02:09$user->delete, the user id is still around. Let me just make an example to
02:15make that clear to you. We're going to create a new user called, johnsmith, and
02:19then right afterwards, we're going to delete it. Now it should probably be id
02:233, this time I'm going to create a new one. So we'll create it and then
02:26immediately delete it, but I'm going to do one other step, which is echo
02:31$user->first_name.
02:33Now notice that we have already done the delete, we have deleted from the
02:36database, it's gone, but we still have the instance of our object around. So
02:41let's go ahead and try this. Let's open up our Firefox, save just one more
02:46time, make sure he is still gone, and test.php, we'll run it and it comes back
02:51and still says John.
02:53So even though we refresh it, and he is not there in the database, it was still
02:57able to pull up his first name, because that instance of the class, the PHP
03:03instance, still exists, even though we have told SQL, hey, do a database delete
03:08for us. Now, most times that's not a big deal and in fact, sometimes it can be
03:12really useful because we could say, for example, that this was deleted.
03:17So it can actually be a little bit helpful to have the instantiation still
03:21around where we have access to it, but don't be fooled into thinking that, now
03:24you could do, for example, an update on it, because it doesn't exist in the
03:27database anymore. So I just wanted to make sure that that point is clear.
03:31In the next movie, let's take a look at how we can abstract what we have just
03:34done in the user module, so that we can apply it to other classes as well.
Collapse this transcript
Abstracting the database table name
00:00We have now successfully coded the Create, Update and Delete methods on our
00:04user class. Ideally, what we would like to have is these methods be abstract
00:09enough that we would be able to use them in any of our classes, so that we
00:13could perform the same SQL actions in our photograph class and our comment class,
00:18which we're going to be creating a little while.
00:20We talked earlier about late static bindings and the problems that it presents,
00:23you want to go back and review that movie if you have any questions about it.
00:26But eventually, we'll be able to push all of these common database methods up
00:31into the database object class. Once we get to PHP 5.3, late static bindings
00:36are available.
00:37Until then, the approach that we're going to use is to put all of those into
00:41the user class, and then copy and paste the exact same code into our additional
00:46classes. Now that's repeating ourself and that's not really a great idea in
00:50programming, but it will have to make do until we have the ability to move
00:54those up into a class that we can inherit from into each of our subclasses.
00:59So for now, let's work on making our methods more abstract so that they are
01:02reusable and let's start by working on making the database table name,
01:07abstract. So I'm going to start by opening up user.php. Now what I'm actually
01:11talking about here, let me open up create, is that this SQL statement right now
01:18is very specific to user.php. What I would like to do is make it so that it is
01:24reusable in a number of different contexts. One of the first things we want to
01:28do is say well, figure out what table name you ought to have. We see here that
01:33we have a protected static method called, $table_name. So that's what
01:37we're going to use to know what table name this class has.
01:41So, you might be tempted to start out by simply putting in the curly braces and
01:48then table name with self. That's how we would call that. That would be the
01:52static variable $table_name from this object. The problem is that because of
01:58the way PHP parses, this won't work, the curly braces do not work like they do,
02:04if we just simply had, $table_name.
02:06As soon as we put that self in front of it, it's going to break, and so
02:10instead, what we need to do is put in quote period and then period quote. So
02:17we're actually just dropping out of our double quotes for a second to append
02:21together the table name, and this will work for us.
02:24So I'm just going to take that little bit there and copy it, and we'll open up
02:28the update. We'll have the same thing here instead of users. We're going to
02:33drop out of our double quotes, append in the table name, and then open back up
02:38our double quotes again, and same thing for delete.
02:42Now in the case of delete, we're going to open up double quotes just to have
02:45another space. We could also just as easily put the space on this line, and get
02:49rid of those together. That's your choice.
02:51So that then has made these three methods abstract enough that they will figure
02:56out what the table name is based on what class they are in. So the save method
03:01doesn't need any changes, it's just going to call update or create. But again,
03:05this is the first step in allowing us to be able to copy and paste these
03:08methods into another class or to eventually move them up into the database
03:14object superclass.
03:17Now that only got us halfway there though, we also need to work on these
03:21attributes, because the attributes are going to be different, depending on
03:24which class we're talking about.
03:26So in the next movie, we're going to need to spend some time abstracting these attributes.
Collapse this transcript
Abstracting the attributes
00:00In the last movie, we saw how we can make the create, update and delete methods
00:03abstract, the same way we had done with our find methods earlier, so that they
00:06could be used by any class. Now that's going to be enough to make the delete
00:10method abstract, so that we can reuse it, but the create and update methods are
00:13going to use attributes that they submit to SQL. So we'll need to find a way to
00:17also make those attributes abstract. That's a little trickier than what we did with the table name.
00:21So here I'm inside user.php. Inside the create method, you will see that
00:26we have a list of the attributes keys and then down here a list of the attribute
00:31values. Now we would be able to write SQL for both of these, if we can simply
00:35come with an array that had both the attribute keys and values in it. There are
00:39several ways that we could accomplish this. I'm going to show you one.
00:41I am going to come up here above the save method and I'm going to put in a
00:46new method, which is going to be called attributes and this is going to be
00:48protected method. It's simply going to return an associate array of the
00:52attribute keys and their values, instead of names. So I'll say keys.
00:57So if we can return that array, then we'll be able to parse through that array
01:00to come up with these items down here. Now let's take a look at has_attribute
01:05that's right above it. Now in has_ attribute, we were getting a list of the
01:08attributes to see whether an array key existed or not, to see if something had
01:12the attribute. We were doing that using get_object_vars.
01:15So for now, let's just use that. I'm going to copy it, we'll just come down
01:18here, return get_object_vars ($this). So that will now return get_object_vars
01:26as attributes. So we can actually call that here instead $this->attributes.
01:33Now that's essentially the same thing as far as has_attribute is concerned,
01:38but what it gives us is now a method that we can call from other places in our
01:41code to get those same attributes. If we ever make improvements to the way
01:45we find our attributes, which we'll do a little later, then we'll have those
01:49available to us also.
01:50So now that we have our new attributes method, let's go ahead and come down
01:55back into create. Let's start by using that. So we have just $attributes =
01:59$this->attributes that will get all our attributes for us. Then all we have
02:04to do in order to use those attributes is join together the array keys. So we
02:10can use array keys to pull back all the keys of those attributes and join them
02:14together with a comma. That will give us the SQL that we need there.
02:18For the array values down here, we can do something very similar. I'll paste in
02:22join together and we'll include the single quote. Notice I'm starting with a
02:26single quote here, single quote/comma/single quote joining them together. The only difference is
02:31that at the very end, I'll need to make sure that I'll also close everything up
02:35with another '). So that will make sure that the last one has its single quote
02:42after it and parenthesis as well. So that will now join all the values together
02:46and we'll have a valid SQL statement.
02:49Now in the process, I know we lost the code where we were escaping the values for SQL.
02:53We'll want to keep that, but we'll come that in just a second. For now,
02:56let's go on down to the update method and do the same kind of thing. So we'll
03:00come down here and I'll do the same sort of attribute assignment that I was
03:05doing before. But notice that the key value pairs that we're going to need here
03:08are going to be a little more complicated because we can't simply join
03:11the keys together and then join the values together. Instead, they will
03:14interspersed with equal signs between them. We can handle that by iterating
03:18through the attributes and creating a new array. So we'll do that first.
03:22Before we start, we'll make a new array called attribute_pairs. We'll go
03:25through each of the attributes and each one as a key and value, we'll assign
03:30the new attribute_pairs = "{$key} = ' {$value}'". Again, I know it's not escaped;
03:38we'll work on that in a second.
03:40Now we can come down into our SQL statement though and we can do a replacement
03:44for all of these here. We'll join them together with a single comma. Our single
03:49quotes have been taking care of up here. We don't need to worry about those.
03:52We're going to join attribute_pairs now, not attributes, and that will give us
03:56the list that we're looking for.
03:57Now there is one more thing we need to be careful about, which is that when we
04:00join these together we'll get a comma space between them, but whatever that
04:04last value is will have a single quote and then it will start the word WHERE.
04:10We need to make sure that our SQL is valid, so we'll put a space in front of
04:13WHERE. So it will be single quote as the last item and then WHERE.
04:17That's something that frequently trips people up, when we're using the multi-line
04:21building up SQL. So you want to be careful about that.
04:24So now we have abstracted out those attributes, but in the process, we lost the
04:28escape_value we did. So let's revisit how we can sanitize those SQL values again.
04:32Let's go back up to attributes here. Now in addition to having an
04:37array of the raw attributes, let's add another version of this that's going to
04:41be a method that will loop through those attributes and escape their values and
04:45return a new array that's actually been sanitized. We'll call it
04:49sanitized_attributes.
04:50So it will simply take the database, go through and make a new array called
04:54clean_attributes by going through each one of the attributes from this method,
05:00the get_object_vars version, and go through each one of them. As it's doing it,
05:05it will escape the value. So now we'll have a set of clean attributes.
05:08Now we have a choice. We can get either the raw ones or we can get the sanitized version.
05:13So anywhere that we're using the attributes to send to SQL, we'll want to use
05:18the new version. So that's going to be sanitized_attributes and down here in
05:24update, same thing. We'll be wanting to pull in the sanitized_attributes.
05:28Up here has_attribute, we can still just use attributes. We're not even
05:31actually looking at the value in this case. So we don't need to worry about
05:34being sanitized; it's not SQL related. But for anywhere where we're going to be
05:38submitting values to SQL, we now have the ability to have attributes that are
05:42pre-sanitized for us.
05:43Now there is one more thing. Here inside attributes, get_object_vars is not
05:48the best way to get the list of attributes. In the next movie, we'll examine
05:51the problems with get_object_vars and we'll talk about a better approach.
Collapse this transcript
Finding the database attributes
00:00In the last movie, we began the process of abstracting our attributes that we
00:03were using in our create and update methods, so that we can reuse those
00:07methods inside other classes. But when we did that, we used get_object_vars
00:12and that present some problems. In this movie, we'll look at what those
00:14problems are and find our way around them.
00:16As we have mentioned before, the problem with get_object_vars is that it
00:20returns an associative array with all attributes for the class. That includes
00:24attributes that may not have corresponding database fields and it also includes
00:29private and protected attributes. Because we're calling get_object_vars from
00:32inside the class, so it gives us all the object variables that it has access to.
00:37That includes those private and protected ones.
00:40That's two good reasons why it's not going to work for us. There are some ways
00:44that you can get_object_vars from outside the class to exclude the private
00:48and protected ones. You can find out information about that by looking at the
00:51php.net website, but that's still not going to rule out the case, when there
00:55might be attributes that we want in our class and we want to be able to use,
00:59but they don't have corresponding database fields. Because of that, really the
01:03easiest way to work around this problem is going to be to create another
01:07attribute that is going to keep a list of all the attributes that have database
01:12fields associated with them.
01:13So let's do that. Let's go up here to the top and we'll put another static
01:17variable in here. I'm going to call it db_fields. So inside db_fields is an
01:22array and that array is going to be a list of all of the fields that are
01:27database fields. That will keep track of it. We'll have access to it then.
01:31So now what we want to do is come back and actually recode attributes to make
01:36use of that. So what we'll do is we'll go through each one of those and
01:40we'll ask the object to return it's value and put it into an associative array.
01:44We know how to do this in PHP. So we have an empty array, then we go through those
01:48database fields. For each one, if the property exists, then we're going to
01:53setup the associative array equal to whatever that value of the field is.
01:58Now notice here, I'm using this and I'm using the dynamic field. That's how
02:03we're able to do that. We're able to use a dynamic variable here. Don't let
02:06that thrill you. In the end, we return that new array that we have put together
02:10of all those attributes, as our attributes.
02:14Now, of course, the drawback to this approach is that you have to actually list
02:17those fields out one-by-one at the top of each of our classes. Now if we had
02:21something that was really complex, we had a big object with lots and lots of
02:25attributes, that might become cumbersome. In that case, you can write something
02:28that was more complex, that might use something like SQL's show_fields_from,
02:33what the users table. So show_fields_ from_ users would return a list. So we can
02:37parse that and then build that array dynamically.
02:40But for our purposes, because we're going to be working with fairly simple
02:43tables. Every time we create one of those database tables, we're going to go
02:47ahead and list off, in the class, what the database fields are. That's going to
02:51be a nice easy way for us to handle this problem. It will circumvent those
02:54problems that we have with get_object_vars.
02:57So once we save that, we now have a user class that is capable of all of the CRUD.
03:01We can create records, we can read them, and we did that with our
03:05find_all, find_by_id, find_by_sql. And we can instantiate them. That's part of
03:10the reading and turning them into objects. We also now know how to update and delete them.
03:16So we now have a complete well-rounded ability to interact with our database by
03:20using our user class. Now that we have finished abstracting out the create
03:23and update methods so that they are going to be reusable inside other
03:27classes, we're ready to move to one of those other classes. That's the
03:31photograph class and that's what we'll work on in the next chapter.
Collapse this transcript
10. The Photograph Class
Starting the Photograph class
00:00Now that we have all the CRUD written for our user class, we're ready to apply
00:05those methods to our photograph class. Now it's taken us a long time to get to
00:09this point, but in a way, this is what we have been working towards all along.
00:12The intermediate PHP we learned, the object oriented skills, working with files
00:17and directories, uploading files and then developing all of the CRUD for the
00:21user model, all of that is so that we're able now to work with the photograph class,
00:25which will allow us to upload photographs and work with them in an
00:29object oriented way using those same methods that we just wrote.
00:32Now there is one key difference between uploading photographs with the
00:35photograph class that we're about to write and the file uploading that we did a
00:39view chapters ago. That's why we'll be using the database in order to keep
00:42track of the files once they are uploaded.
00:44Previously, we just simply uploaded them to the file system and did not have a
00:47database keeping track of them. We're going to combine our file uploading
00:50skills with the create method that we just completed. Now there are few
00:54reasons why storing image information in the database is going to be better
00:57than relying on the file system alone.
00:59First, it's easier to search and sort images using SQL. Second, we're going to
01:04then be able to relate other database records to our photographs records. So
01:09for example, when we let people make comments on our photos, we'll able to have
01:13an entry in the database for photograph and then have entries for comments that
01:17are related to it.
01:18Since we're going to need a database, let's start out by creating that. Now if
01:21you remember back in chapter 5 when we created our users table, we also granted
01:26access privileges to gallery as a user and we gave it a password. You might
01:31have given it something different than me. That's fine, but you can look in
01:34that config.php to mind yourself of what it was.
01:36So we have the user, the password and the database name. We're going to use
01:40those now, instead of logging in as root. Now you could log in as root. If
01:44those doesn't work for you, that's fine, but I'm going to open up Terminal here.
01:48In order to get to those, we're just going to do mysql -u for the user and
01:53instead of root, it's going to be gallery and then --password= and here is my
01:58password for gallery and then the database that we want to log in to. So that
02:02will put us directly in that database logged in as gallery. Since we said Grant
02:06All Privileges, we have the ability to go ahead and create tables there as well.
02:11So the table that we want to create, it's going to look like this. CREATE TABLE
02:14photographs. We're going to have an id NOT NULL AUTO_INCREMENT PRIMARY KEY.
02:19The file name, which will be the name of the image file. I went ahead and told that
02:24it's just VARCHAR (255). The image type. You remember the type is one of the
02:30things that is returned to us automatically. It's the mine type; we get that
02:33information when we do a file upload.
02:35So we'll go head and store it in the database, as well as the size, and then
02:39the last thing is going to be caption. That's going to be something that the
02:41user will be able to supply. They can caption the photograph. I went ahead and
02:45just set that also. It has a 255 character limit, but you can make it text if
02:49you wanted to allow people to write much longer description. So for now,
02:53I'm just going to limit it 255.
02:54So it says Query OK. So it has now created the table and I can confirm that
02:58with SHOW TABLES. So now I have both photographs and users. If say SHOW FIELDS
03:05FROM photographs, we can actually see those and see that they were all created properly.
03:11So let's quit out of my SQL now and let's switch back over to our main website.
03:17Let's create a new file in the includes directory. So I'll open up a new
03:21TextMate file and save it, not in the btb_sandbox but inside photo_gallery,
03:27includes and we're going to call it photograph.php.
03:32This is where we're going to put our php which is going to define, class
03:38Photograph extends DatabaseObject. Even though there is nothing in
03:43DatabaseObject, there will be some day. So we'll go head and do that for now.
03:47Then at the top, you can already guess what our attributes are going to look like.
03:51It's very similar to what we did for user. If you need to open up user as
03:54a comparison, put those side-by-side and you can see that we went ahead and
03:58declared table name, we declared what database fields and then each of those
04:02database fields gets an attribute as well.
04:04Notice also here that there is this nice require_once for the database. That's
04:08a good idea. Since we're going to be using the database class, we'll go head
04:11and require it at the top. Then last of all, all of these common database methods
04:16that we wrote before, they should now all be abstracted so that we can reuse them.
04:22So all of them should work. I'm just going to copy them and paste them. Again,
04:25once we have database object working, we won't need to do that any more. So for
04:30now, I'll just put all those in there, I can collapse all these down, just so
04:33they are out of the way. Here we go. So now we have got our common database
04:43methods. We're ready to add any new methods that we need to photograph.
04:47Now there is one other thing that I want us to take care of, which is if you
04:49remember, when we did the initialize here, you will remember that we required
04:54the user file. So we'll want to do the same thing for photograph, so that it
04:58gets loaded. Remember that we do have a function called autoload, which is
05:01here, which will take care of trying to find it.
05:04But since we know we want to load it, let's go ahead and just specifically put
05:07that in and initialize, so that we make sure that the photograph class gets
05:10loaded up. The very last thing is where we're going to upload these files to.
05:14We want to upload them into the photo_ gallery, into public, into images and
05:18that is where we're going to put them.
05:19So we want to make sure that that's writable. So let's go back here and let's
05:23just go into... for me that's Sites/ photo_gallery and inside public. We should
05:32be able to see images. So that is the folder. We want to make sure that is
05:37writable by our web server. But right now, it doesn't look like it is.
05:40So we want to do something like sudo chown www.images. That for me, well at my
05:46web server, which runs as www, I'm going to put my password. It will let it be
05:52able to be the owner of that file. Now we have talked about privileges before.
05:55If you want to do something different, you want to make trimod 777, that works
05:59just as well. But the important thing is to make sure if we're about to start
06:02uploading images into this folder, that's the web sever has the ability to put them there.
06:07Once we do, then we're ready to go back to our photograph class and start
06:10making the customization that's going to allow it to handle uploaded files.
06:14That's what we'll do in the next movie.
Collapse this transcript
Coding the Photograph class
00:00In the last movie, we started creating our photograph class and we did all of
00:04the basic work that we need to do: to have a class, to have it inherit from
00:08database object, to have it being loaded by initialize, and to go ahead and
00:12bring in all of the common database methods that we used for the user class
00:18into our photograph class.
00:20Now we want to start customizing it so that we'll able to upload photographs.
00:24Before we dive into photograph.php, let's take a look back at btb_sandbox and
00:29open up upload.php. I'm just going to shrink it down a little bit, just so that
00:33it all fits on the screen here.
00:34Now what we essentially want to do is take all of this code here that takes
00:38care of the processing and uploading of files and move that into our photograph class.
00:44So you can always refer back to this if you want to take a look at what we did,
00:47but we want to take that and now make that object oriented.
00:50Now I'm going to be writing it from scratch. So I'm not going to be using it as a
00:53reference, but we're going to open up photograph.php. To get started,
00:57we're going to keep track of a couple of variables that we were using in that
01:01upload.php page.
01:02The temp_path, remember that's something that is provided to us when we upload
01:06a file. We'll make that an attribute, so that we can actually store it in the
01:09class. We can ask the class for its temp _path, where the file is before it's in
01:14its final destination.
01:15Now because it's only a sort of temporary working variable that we're going to
01:19be using, we're going to make it private so that the class knows how to work
01:22with it and can use it. But it's now something that we're ever going to need
01:25from outside the class. We'll only work with files, once they are located in
01:28their final resting place.
01:30Then we're going to have upload directory, which I went head and said, should
01:33be protected. We can make it public. That's fine. If it needs to change for
01:38some reason, you can make it public. So this is going to make it, so that both
01:41photograph and any of its sub-classes would be able to use it. I'm going to go
01:45ahead and set that equal to "images".
01:47The next attribute that we're going to use is also going to look familiar to you.
01:50I'm going to go ahead and put upload_errors as one of our attributes so
01:54that we have access to all of those upload_errors right there from inside of
01:58our class. It knows what things went wrong.
02:00Then I'm going to add one more that's not familiar to you but that we'll be
02:03making use of, which is one is simply called errors. So errors equals and it's
02:08just an empty array. That's going to be initialized as an empty array. Then
02:12what we can do is as we're going to through and trying to move the upload or
02:16save the upload to the database, we can catalog those errors, we can keep track
02:20of them. Then return them to the user and say, hey! Here is what went wrong, by
02:25looking at the list of errors. That way we're not limited to just these
02:29upload_errors, but we could add our own errors as well.
02:32So what we're interested in coding now is this public function attach_file.
02:37This is a method that's going to allow us to pass in all of FILE. And then
02:43whatever name we have given it, I'm going to call it an uploaded file as an
02:46argument and that is going to be $file. It's going to perform some error
02:49checking on it, it's going to set all of these object attributes up here:
02:52filename, type, size, temp_path. All of that is going to get set by using those
02:58parameters that we're sent down. Then we'll have an object that's ready to be
03:02saved in the database.
03:04Now don't worry about saving anything to the database yet, we'll do that in the
03:06second step, in the same way that we created a user and we gave it a user name,
03:11we gave it a password and everything. Then we did it separately, we saved it,
03:15we're going to do same thing here. We're going to instantiate a file that is
03:20ready to be saved and then we'll actually do the saving in a separate step. So
03:25let's take a shot at these steps.
03:26So first of all, let's say, set object attributes to the form parameters. We
03:30should be able to figure this out pretty easily. You can look at upload.php to
03:34figure that out. Essentially, we just wanted to take each of those variables,
03:37temp_path, filename, type and size, and set them equal to the information
03:41that's been passed in using $_FILE (['uploaded_file']).
03:44So we're going to take you to one of those. This is same as if we had this bit
03:49here in front of tmp_name and so on. You will see that we're using basename,
03:54just like we did before in upload.php. But we don't have any error checking in here.
03:58So let's put some very basic error checking in.
04:01The first check that I'm going to do is if there has not been a file sent in or
04:06if it's empty or if it's not an array, then something went wrong. There is some
04:10argument problem with file and we can't use it. So therefore we'll just say no
04:13file was uploaded and return false.
04:16So the second thing I want to check is going to be, if php returned an
04:20upload_error. So if the file array that come back has an error and that error
04:26is not 0, remember, 0 is success, then php found a problem. So we'll just
04:30report back, what PHP said was wrong. We'll do that by taking that
04:34upload_errors, finding the one that corresponds to the value that we get back,
04:39and putting that inside our errors array and return false. Each time it returns false,
04:43we'll return but we'll also be able to check errors to see what went wrong.
04:48Then last of all, of course, would just be simply, if everything worked okay.
04:52That is the case here, where we didn't do these. Now just didn't those and
04:59close my curly braces. I make sure my curly braces are all lined up.
05:04So there we go.
05:05The very last thing I want to do is just at the very bottom, if this all
05:09succeeds, then let's go ahead and just make sure we return true as a final
05:12value. So it's consistent. We return false, if it didn't work. We return true,
05:16if it did work. All the attributes have been set accordingly in the process.
05:20Now we don't have a mechanism for testing this yet. You could go head and write
05:23it on your own, if you wanted. But I think you can feel pretty confident that
05:26it's going to work correctly because we're pretty much just doing the same
05:29thing, we did in that upload.php file. There is nothing that is sort of too out
05:33of left field here. So there may be syntax errors. You might want to just
05:36double check all your typing and make sure you get on it right.
05:39But if you put everything in there correctly, then we should be able just to
05:42instantiate a new photograph, tell it to attach the file using this file, and
05:47then we'll be able say Save as a next step. Saving is what we'll learn how to
05:51do in the next movie.
Collapse this transcript
Saving photographs
00:00Now that we have written the method that will take the information we have been
00:03given in the form parameters about an uploaded file and instantiate an object
00:07from it, the next step is to actually do the saving. And in this case,
00:13doing the saving is going to involve two steps: moving the file to its final and
00:17permanent location, and recording an entry in the database about where it's located.
00:21Now there are a couple of different ways that we could do the save. We could
00:25write a method that was something like this: function save with file.
00:28In that way, we don't interfere with the save that we already have in our common
00:32database methods down here, and instead have something that's completely safe,
00:36that will take care of this unique situation that we have here.
00:39We also if we were using database object, if we had late static bindings and
00:44we had moved all of those common methods up there, we could simply use save and
00:49overwrite the inherited method, and if we ever want it access to the original one,
00:54we can call it using parent and then save, and that will allow us to do
00:58the save that was in the parent method.
01:00Those are both valid approaches. What I'm going to do instead is actually just
01:04overwrite the existing save method. You may remember we had save down here that
01:09just simply says, well, the record may or may not have an ID and based on that,
01:14we're going to do update or create. Well, I'm going to give it a little more
01:16functionality in the case of photograph, so it's going to be a little bit different.
01:20I am going to just comment all of that out and I'm going to say replace with a
01:26custom save, just to remind myself, and then up here, I'm actually going to
01:30right a new method. I'll go ahead and paste down some comments showing kind of
01:34what we're after. We're still going to do the same whether or not it has an ID.
01:38If it has an ID then just update it. In that case, we're probably just updating
01:41the caption on it, we'll assume that the file is probably not moving, and
01:45we'll try and keep that in mind really just to update the caption.
01:51Then we'll have the second one which is where the mid of it will be where we'll
01:54make sure that there are no errors, and if there are no errors, then
01:57we'll attempt to move to the file, and if the move succeeds, then we'll save a
02:02corresponding entry to the database, and the way that it will save that
02:05corresponding entry is to still use that create method. We still have that
02:08available to us.
02:09So we still can make use of that but we're going to do a little bit of meteor
02:13stuff before we get there. So let's start to write some of that code. Make sure
02:16that there are no errors. Well, first of all, we can't save if there are
02:19preexisting errors, so we can just simply check and make sure that our error
02:22array is already empty. Then we set that the caption has to be limited to 255
02:27characters. If you set here up the same way, then you want to put something like that.
02:32We can add an error in that case if its greater than 255. We know that
02:36we're going to need to know the temporary location of the file and we're going to
02:40need to know the file name. So in that case we would also want to stop this
02:44method from happening and it will return false and tell what the errors were.
02:47Now if all of that works, then we're going to be ready to figure out what our
02:50target path ought to be. So target path I set is the side route, directory
02:55separator inside public, and then inside where our the upload directory is.
02:59In this case, it's images and then the directory separator, and then whatever
03:02the file name is.
03:03Now once we have that and we know where we're going to be putting this file, we
03:07can do an additional error check, which is to make sure the file does not
03:10already exist. That's another reason that we might want to stop the process
03:13from happening. If all of that works, then we're in a place where we can
03:18actually attempt to move the file.
03:20We know how to do that from before with move uploaded file, so we'll try and
03:24move from the temporary path to our target path and if that succeeds, then
03:29we'll have success else failure, and we can already say that if it succeeds,
03:38then that is where this is going to go, right. We're going to create the
03:40database entry. If not, we're going to fail, we're going to add a little bit
03:43more there as well.
03:45If the file is not moved, let's go ahead and just put in an error that will say
03:48the file upload failed and return false. If it does moves, then we're going to
03:52try and create the database entry and we'll wrap that it in an if statement. So
03:57if the create takes place successfully, so then we're going to do couple of
04:02other things.
04:03The first is unset the temp_path. We don't need anymore. It was just a
04:07temporary variable, but that will help us know that it was moved successfully,
04:11and finally return true, just to let us know. If you have been returning false
04:15for every other case. This is the one case where we'll return true and
04:19I'll just add a note here to remind us that that's why we deleted temp_path because
04:23the file isn't there anymore; it has been moved.
04:26So that takes care of all the steps for moving the photograph go back and
04:30review if you need to. I'll just scroll up at the top here. If the ID is
04:34already set, then it's an update. Otherwise, we're going to go through and make
04:37sure there is no existing errors.
04:39Make sure the caption is okay, it doesn't necessarily have to have a caption
04:43but it can't be more than 255 characters, and make sure that we're not going to
04:48run into problems with not having the right file information, make sure the
04:51file does not already exist, and then finally if all of that is true, go ahead
04:56and attempt to move the file to the new place and if that happens, we're going
05:00to put the entry in the database.
05:02Now that's a lot of code, so you want to definitely look over it carefully,
05:05debug it, it's quite possible that I have made a bug in there, and I'll have to
05:08debug in just a second, but what we're going to do now in the next movie is
05:12actually write the upload page that's going to be the form that'll allow us to
05:16upload photographs, and try out these two methods: the instantiation and the
05:20saving of our photograph.
Collapse this transcript
Uploading photographs
00:00In the last movie, we finished coding the photograph class, which is going to
00:03handle most of the grunt work for us for uploading files. Now in this movie
00:07what we need to do is code the form that is going to allow us to upload files
00:11and the form processing, so that we can try our new class out and see if we can
00:14actually upload images.
00:16Now before we start writing up that web form, I just want to point out to you
00:19that I have a new folder on my desktop called photos and this just contains
00:22a few samples images that we're going to be using to upload to our photo gallery.
00:26These are included with your exercise files.
00:28If you have a access to the exercise files, you can use these photos or you can
00:31use your own photos; it really doesn't matter. You'll notice I have made these
00:34all a fairly small file size, and file size is something we want to keep in
00:38mind when we're uploading files with PHP because we do specify what the maximum
00:42file size is.
00:43So don't pick something that is like 5MB file and trying to upload it, if you
00:47haven't given PHP permission to upload things that are 5MB large. So I want
00:52something small, just so that I make sure that we don't run into problems.
00:54So now let us start writing that form. Since, we're not going to be using
00:58test.php anymore. We're actually going to just repurpose that. We'll make it
01:02into photo_upload that will be the new name, and I'll open it up, and it just
01:07take all of these old PHP that was in there out. So we still have the
01:11initialization taking place, we're still making sure someone is logged in, and
01:14we have our header and footer.
01:16Now we're ready to put in our form. So I'm going to paste in the beginning of
01:19the form for us just something very simple, similar to what we saw before. The
01:24form is simply going to be posting to itself photoupload.php. Remember that we
01:30have to specify the enclosure type as multi-part form data because we're going
01:33to have an enclosed file.
01:35I have my hidden input type here with the file size of roughly a megabyte, and
01:40then I have my input for my file field, and I'll call that, file upload. Just
01:45remember that name, we'll be reusing that. Then I'm going to let the user
01:47specify caption that it should go with the photo, and the submit button,
01:51nothing out of the ordinary there.
01:52Now let us start improving it with some PHP. To start with, I'm just going to
01:56put in some PHP tags here at the top and I want you to go ahead and declare the
02:01maximum file size up here at the top where it's nice and easy for me to see. In
02:05that way down here, we can simply call that value "<?php echo $max_file_size; "
02:12/>. I'll close our PHP tags, and that will put whatever max_file_size we put up here.
02:18It will just drop it down in here automatically.
02:21Now you may want to note, max_file_size is a potential candidate for something
02:24that could be a static attribute of our photograph class. We could be pulling
02:28it statically from the photograph class. I have decided to go ahead and make it
02:32just for this page.
02:33Now we're really take care of our form processing. So I'm just going to drop
02:36down here. There we go. So it's just a real simple. If the post is set then
02:42we're going to do the form processing, and if the form has been submitted, the
02:45first thing we want to do is we want to instantiate a new photograph and we can
02:51attach the caption to it, photo caption. It's going to be equal to and we're
02:57going to get the post value for caption and of our post super global.
03:02We have been want to attach the photo to it, and we can do that with our method
03:05we called attach file and we'll pass in from the super global files, file
03:13upload, and remember that's got to match up with what's here. File upload is
03:17where we get that.
03:18So we're going to pass in that whole array to get sent with files to attach file.
03:22And it will handle it from there. We don't have to do anything else.
03:25And now we have an object that has the right caption. It has all the information
03:30about the file that was uploaded.
03:31So the only thing left to do is just to see if it's saved or not. So if photo
03:36saved, then success, else failure and in each of these cases for success and
03:47failure, let's just provide a real simple message, the photograph was
03:51successfully uploaded, or if it wasn't, we'll join together whatever errors the object has.
03:56Remember we have that array of errors. So we'll just take them and join them
03:59together with the br tag and that will be the message that we give back. Of
04:02course if we're going to do that, then we need a way to actually output that
04:06message. So let's come down here right above our form, and we'll put in our
04:10output message helper, and it will send-in message.
04:12Now for sending in the value of message, we need to make sure we have that
04:16variable set, and if it's a post operation, it will get set but if not, it
04:21won't. So let's just make sure that we don't run into problems by having
04:24message equals quote to start with. So it should always, at least be
04:28initialized with an empty string.
04:30Now you may notice here that I'm not doing an if attach file to see what are
04:34the attached file succeeded. I certainly could but what happens with attached
04:38file, besides the fact that it returns true or false is that it sets errors for us.
04:43It sets them in that errors array. And if you remember, I coded the photos
04:46save method so the very first thing it does is it checks to see if there are
04:50existing errors.
04:51So it does the same thing as if I done it if then statement, this takes care of it.
04:55Now if we wrote our attach file differently, we might want to code it
04:58differently, but I'm taking advantage of the fact that those errors are set and
05:02the save will notice and fail. So I don't have to do a separate if/then statement here.
05:07So now that we have all these, let us try it out and see if can debug our code
05:11in the process. I'll save it, close it up, and we'll open up Firefox. Here it is.
05:16Let's go to photo gallery, public, admin, photoupload.php, and that is our
05:24page it wants me to log in you may already be logged in, secret pwd, and let me
05:31try again to photoupload.php.
05:35So here we're with our photo upload, browse, and I can browse to the first one
05:39and I'll pick bamboo.jpg and we'll just give it a caption of bamboo. Caption
05:45cannot be more than 255 characters long, well I definitely was under that 255,
05:49so we have a bug in there, let's open up photograph.php, and here we're with
05:54the caption and sure enough I have it. If the link is less than 255,
05:58and I should be saying it's greater than 255, so there is a bug. We'll close that up.
06:03Let us try reloading the page and we'll re-browse to bamboo and caption bamboo.
06:11Upload, photograph uploaded successfully. We have not written anything to see
06:15those. So we just have to take its word for it, but we can also check by
06:18checking in with MySQL and I'll use php my admin so that I can do that quickly.
06:22We will go into photographs and browse. And sure enough here is bamboo.jpg,
06:28image\jpeg, the size, and the caption. It all got entered correctly and we can
06:33go here and see that it is now in our images. It did actually upload the file.
06:37So now that our file upload is working we're ready to have PHP actually show us
06:42these photographs. In the next movie, we'll work on listing up the photographs
Collapse this transcript
Listing photographs
00:00Now that we have the working photograph class and we have a form and form
00:04processing that will upload photographs, what we really need is something in
00:07the admin area that will let us view the photographs that we have uploaded and
00:11that's what we're going to create in this movie.
00:12Now I strongly suggest that you pause the movie now and try it on your own.
00:17You have all of the skills that you need to be able to do this already without
00:20my help. Then when you are ready come back and I'll show you how I did it and
00:24I'll make a few other extra points along the way that you want to see. I really
00:27think it is going to be best if you try it on your own because I think
00:30you will be able to utilize a lot of that knowledge and help make sure that it's
00:33really firmly cemented in your head.
00:36Now hopefully you did pause the movie, and you tried it for yourself and
00:39I'm going to show you the way that I came up with the solution. I'm going to open up TextMate,
00:43we'll open a new window, and I'm just going to paste in the code.
00:46We're going to just take a look at it, we have got the initialize step at the
00:48top so we get all of our classes and everything brought in.
00:51We make sure that the user is logged in and then we just find all the
00:54photographs, and we call our static find all method to do that. Now we have a
00:58variable set that's actually an array of instances that we created. We now have
01:03an array that we can work with. I'll simply make a table down here that will go
01:06through each one. I'll use foreach to loop through them.
01:09So for each element in the array photos, call each one with the variable photo
01:14and that will be the name of the object as it loops to the array, and then for
01:18each one output its file name, its caption, its size, and its type. Now notice
01:22that I'm using colon notation here on the foreach, not the curly brackets. So
01:26that means down here, instead of just having the closing curly brackets I have
01:30int fro each with the semicolon to wrap that up I can use either notation.
01:34Last of all, I have got photoupload. php as a link that will just take me to
01:38upload a new photograph. That's a nice user friendly feature, then notice that
01:42I haven't put anything yet for the image source, so we can't actually see the image yet.
01:46I haven't told it what to display. I'll just put an empty image tag in there.
01:50Now let's stop and think about what the image source ought to be for a second.
01:53We're inside of our admin folder. So we need to go back a directory to get into images.
01:59So we can do ..images and then whatever the file name is.
02:04That will work but I think it's not the best way to do it and let me show you, why?
02:08If we open up photograph.php and we go up here at the top, you will see that
02:12we specified the upload directory here. We gave our class knowledge about what its
02:17upload directory is. If we were to change that some day, let's say to photos,
02:22then the class would say, hey, I'm now looking in photos for everything
02:25I'm uploading, all my new images in to this folder.
02:28But we would have broken this page, this page would still be looking in images
02:33so a better way to do it would be to ask the class to handle it for you, and
02:38that way that knowledge just stays inside the class. So right here below the
02:41Save, I'm going to put in a new method. I'm going to call public function
02:45image_path and that's going to take that upload directory with the directory
02:49separator and the file name. It's going to do it for me. In that way now, using
02:53that object-oriented programming, I can just call image_path back over here and
02:57I'll get both.
02:58So let us do that real quick, php echo, $photo->image and asking for is
03:04image_path. You have to have the parenthesis now because the function is not an
03:08attribute so we have to have those parenthesis and we'll close the php tag.
03:12That will now locate the file and if that directory ever should move for some
03:16reason, we only have to tell the class about it, and it will trickle down
03:19everywhere else.
03:20Now I think it's acceptable to have ../ in front of it because we're in the
03:24admin directory and we do want to back out of that directory first. So let's
03:27save this. Not in my includes file. Let's go photo gallery, public, admin, and
03:34let us call it list photos.php. There we are.
03:41So let's take a look at this in a browser. Let's switch over to Firefox real
03:45quick. Here we're and instead of photo upload now, we're going to go to list
03:49photos. Call the undefined method photograph image path. That I have not saved it.
03:55Let's try saving that. There we go. Now it worked.
03:58So there we go, now we see the image. I told it to be smaller just by telling
04:02its size 100 so that shrunk it down. We'll work being able to see full size
04:06images later, but we can see all the information. One thing that jumps out of
04:09me is that this size number is kind of meaningless. That's in bytes,
04:13but normally we don't work in bytes so it will be a lot better if we had a nicer way to see that.
04:18So instead of just echoing the photo size, we could do something like this.
04:22If the size is greater than 1024, then express it as kilobytes. Otherwise, express
04:29it as bytes and go ahead and write bytes after it. Now that's fine. That works.
04:32That's certainly an improvement, but I have in mind an even better way that
04:36really uses the strength of object-oriented programming.
04:39There might be a lot of other cases where we want to display the size in other
04:42context. So why do we write this every time? It's better to put it into the
04:47object itself. So let's do that, let's go back to the photograph, and below
04:51image path, I'm going to add a new method which is going to be called
04:55size_as_text and it will go through and it will say well if this object size is
05:00less than 1024, display it as bytes. If it's less than a megabyte, then display
05:06it as kilobytes and we'll round that number off after dividing it by how many
05:10bytes, otherwise, we'll assume that it is megabytes and we'll round it to one
05:15decimal place and display it as megabytes.
05:18So let's try that out that's our new method size as text. So now instead of
05:22calling size we can call size_as_ text and don't forget we need those
05:26parenthesis after it because it is a function not an attribute. So let's try
05:31that now and let's reload the page. And you know, that's something that's a
05:33little user friendly, and we see the strength and power of object-oriented
05:37programming because we're able to push that up into the object.
05:40Now we have access to that method anytime we want, it's right there just as
05:45accessible as an attribute is. In the next movie, we'll have the upload new
05:49photograph redirect immediately back to this page and see how we can make some
05:53improvements where that's concerned.
Collapse this transcript
Storing messages in the Session class
00:00In this movie we're going to see how we can make an improvement to the way
00:03our photographs are being uploaded by storing messages in the session class.
00:07I'll show you what I mean. So we have coded where we can upload a new photograph,
00:11but when we successfully upload a photograph, it just comes back to this page
00:14right now and shows a message saying, "Hey! The photograph has been uploaded."
00:17Let's try with Buddhas and we can do Buddhas, Upload. So it sends us a message
00:23here but what we'd really like is for it to redirect us to this other page,
00:28the List page. So we can do that, we know how to do that here by instead of having
00:31this message right after it, we'll do our redirect_to function that we wrote
00:38and then we can go to list_photos.php and that will redirect us.
00:42But when we get redirected, we'll lose this message. The message will disappear
00:47during the redirect, because the redirect is actually a new request.
00:49What we're actually doing with that function is sending a new set of headers to the browser.
00:54So we're telling the browser, "Hey! Here comes a new page and we're
00:57starting the whole cycle over again." It's a new request response cycle. So
01:01this gets lost. So we need a way to store this and the way we store things in
01:06a stateless web environment is by using session. So what we want to do is create
01:10a mechanism inside session that will hang on to those values and keep them around for us.
01:16Inside session, I'm going to make a new attribute and we're just going to call
01:19it message and that will allow us to assign something to message and then
01:24we can put it in a session and get it back out when we're done. So the first thing
01:29we're going to need to do is right something in the construct method so that
01:33automatically when we're checking the login that we also run another method
01:37called check_message and that will check and see if we have any messages that
01:42have previously been set.
01:43So let's jump down here and we'll put in a new private function called
01:48check_message just like we had check_login, this will check message,
01:51check to see if there is something stored. So if some message has been set, then set the
01:56attribute message equal to whatever is there and clear it. If there is nothing there,
02:01then just initialize Message with an empty string, so that we don't get
02:05errors. It always has a value; the value is just no message.
02:08So that will allows us to set it up as soon as our session is created. Remember
02:12we're doing that automatically down here so that a new instance is created,
02:17it will assign any values for a message that were waiting for us.
02:20Now we have a way to check the message and get it established as an attribute,
02:25but now we also need a way to set the message. So I'm going to make a new
02:28public function here and I'm going to call it just message. Not set message,
02:32message, and that's because I'm going to have it do dual duty.
02:35So PHP can tell the difference between the function called message and the
02:39attribute called message. That's not a problem. I have got an argument here
02:43that's msg. That is going to be the text of the message that is sent.
02:45It's optional. It may not be sent. In fact, if it is not empty and a string has been
02:50provided to it as an argument, then we need to set the message. In which case,
02:55 we'll use session message equals whatever the message was.
02:59If it was empty, then it is a get message and we should return whatever message
03:03was there, whatever is in the attribute. So this function can do both.
03:05It can both set a value and get a value depending on whether or not an argument is
03:10provided here.
03:11I am just doing it to show you the technique and show you how it can work.
03:14You also could have something that was called set_message and something that was
03:18called get_message. Now, make sure you understand why just simply setting the
03:22attribute message equal to the message would not work. We have to actually
03:25store it in session.
03:27That doesn't get stored for us automatically. We have to make this assignment,
03:31specifically this assignment, in this way, to put it in a session file.
03:36Otherwise, it's just an attribute of a class called session. It's not actually
03:40in the real session, so make sure you understand that.
03:43So now that we have that in there, we have the ability to get messages,
03:46we have the ability to set messages, everything should be working. I'm going to do one
03:49more thing for convenience down here. I'm going to say message equals whatever
03:53the $session->message with the parentheses. So it's calling that function.
03:59That's what it is going to pull out and set to this variable.
04:01In that way, I had this variable nice and easy for me to get to. I don't have
04:04to type all of this out. You could, you could just simply do it this way.
04:08One advantage of doing it this way is I have the ability to overwrite this variable
04:11if I want to, to erase it or to do something else without interfering with
04:14what's in the actual session. So it is up to you if you want to do it this way.
04:18So now that we have that coded into session, let's go back to photo_upload and
04:22let's add that in here. So instead now of setting the message this way, instead
04:27we can say, well, the session message ought to call that function, that method,
04:34and pass in the string to it and that will set message equal to whatever we want.
04:38And now we're ready for the redirect and it will persist across it. Now,
04:42we don't need this anymore; we don't need to set a default message.
04:45That will actually clear anything that was there. We don't want to do that.
04:48Instead, now here our output message will display whatever was in the message
04:53from any previous request. So we want to take that same bit of code and put it
04:57on the list_photos page, so that it's also set there. So throughout our entire
05:01application, that messaging will be available to us. This is always set.
05:05We don't have to set a default value for it. It's always there; it may be empty but it's set.
05:09Let's try it out and see how this all works. I think it will make more sense then.
05:12Notice that I didn't do session message here because I'm not doing a
05:16redirect. What I'm doing is just setting this value right now, overwriting
05:20anything that was there, to be able to output it here.
05:23Let's save that and let's upload a new photo. So this time let's upload
05:29flowers, and we'll call it Flowers, Upload. Photo Uploaded Successfully and
05:35it took me to the new page. Notice how that worked? We set it on that other page.
05:41This is the page that did the processing, photo_upload. We submitted the form
05:44back to itself. But once it was done processing, it stored a value of the
05:48message in a session, redirected, and when it finished on that redirect,
05:53it pulled that value back out, so it was available to us.
05:57Go through it a few times if you need to, to make sure you understand how that
05:59is working. But this is a nice way to be able to pass messages across pages
06:04even though we're redirecting and it is a really important and useful tool to
06:08be able to have when building websites.
06:09Okay, let's go back to the photographs now and in the next movie, I'll show you
06:13how to delete photographs that we have uploaded previously.
Collapse this transcript
Deleting photographs
00:00So now we have fully worked out our mechanism for getting photographs into the
00:03Admin area, we also need a way that we can actually delete photographs when we
00:07decide that we're done with them. That's what we'll do here.
00:10Now, what I have in mind is that we would put something that would just be a
00:12Delete link here and clicking on that Delete link will take us to a page that
00:17will do the deleting for us in an object-oriented way and send us back here
00:22afterwards letting us know that the deletion happened or not.
00:25So let's start by going into this page, let me hide Firefox. So it is going to
00:29be the list_photos page, and I'm going to start by just adding a new column to
00:34the top, &nbsp;. That will just make an empty table cell and then right after
00:40type, we'll put a new one. That's going to be delete_photo.php and remember we
00:44need to pass in the ID into that Get string, so we know which one we're going
00:48to delete. So we'll be able to pull that ID out of the URL and know which one
00:52out of the Get parameters.
00:54So we're going to put in the photo ID there and it will just be a simple Delete link.
00:57That will take care of everything on this list_photos page. Now, we can
01:01actually write the page that is going to do the deleting. I'll just open up
01:04TextMate, we'll make a new page, and I'll paste this in and then I'll show you
01:08real quick after we save it.
01:10So I'll just save it to delete_photo.php. We'll put it in the Admin area so
01:16it is right there with the others. Now that we have the code coloring there,
01:20you'll see we have our typical Initialize at the top, the Load and everything,
01:23check and make sure that we're logged-in, check and make sure that we actually
01:26did receive an ID in that URL string. If not, then just say no photo ID was
01:31provided and redirect to the index page, which is just the menu.
01:35That reminds me that we'll need to just very quickly go to that Index page and
01:38we don't have any messaging here at the top of it. We had that before for
01:41list_photos. Remember we added this output message, I'll just copy and paste
01:46output message here at the top, right above, let's do it right here after the h2.
01:52So we'll do any messages there, if we're going to send messages to it, we
01:55better display them. Then we'll find the photograph, we'll find it by the ID,
02:00GET id, and then we'll take it. If it does exist, if we did find it, and if
02:05we're able to destroy it. We haven't written this method yet, destroy.
02:08We're going to come back to that. So remember we need to write a method called
02:11Destroy in the photograph.
02:13Then if so, the message will be, it was deleted and will redirect to list_photos.
02:17If not, say the photo could not be deleted and redirect to in this case index--
02:21actually I'm going to make that list_photos. I think that probably
02:24makes more sense.
02:25Then last of all, because I don't actually have a header and footer on this
02:28page, I'm just going to do the little bit of housekeeping to make sure that my
02:31database connection is closed. It closes by itself, but it is always a good
02:34practice to do it.
02:35So since there is no HTML here, this page basically does some processing and
02:39then sends us back to one of several pages. So this Destroy method is what
02:45we need to revisit now. So we'll go into the Photograph class and we'll write that Destroy method.
02:50I also want to do something else while we're in there, which is notice that
02:53we're sending in GET, the ID that we got from the URL string. But we're not
02:58doing any kind of checking and find_by_ id before we send it to make sure that
03:03