IntroductionWelcome| 00:03 | Welcome to PHP with MySQL Beyond the
Basics. My name is Kevin Skoglund and
| | 00:07 | I run a web development company called
Nova Fabrica that develops websites and
| | 00:11 | database driven applications. This
tutorial is the sequel to PHP with MySQL
| | 00:16 | Essential Training and I'm going to assume
that you either watch that training or
| | 00:19 | that you already feel comfortable with
the fundamentals of PHP, MySQL and how
| | 00:23 | to use them together to create
pages that interact with databases.
| | 00:26 | In this tutorial, we're going to build on
those essential training skills, to learn how
| | 00:30 | to use PHP and MySQL in
object oriented programming.
| | 00:34 | Object oriented programming or OOP is
a large and important subject that will
| | 00:38 | get most of our attention. We'll also
discover some intermediate PHP techniques
| | 00:42 | like working with the server's file
system, uploading files and sending emails.
| | 00:46 | Now, it's not just theory either. In
this tutorial, we'll build a complete PHP
| | 00:50 | project using all of these
techniques so that you can see the concepts in
| | 00:53 | action and get some experience
using them in real world situations.
| | 00:57 | Now because you aren't a beginner
anymore, there will be times when I ask you
| | 01:00 | to do some basic coding on your own but
it shouldn't be anything that you can't
| | 01:03 | handle. That way, we'll be able to
keep our focus on the techniques that are new.
| | 01:06 | So, I'll assume that you already
know the basics like making sure that
| | 01:09 | an integer is actually an integer or
checking an array is not empty before you try
| | 01:14 | to loop through it.
| | 01:15 | At the end of the tutorial, we'll
have the skeleton of a working web
| | 01:18 | application but one that still needs
improvements and testing using skills
| | 01:22 | that you already have. Enough with the
introductions though. Let's get started
| | 01:25 | learning more about PHP and MySQL.
| | Collapse this transcript |
| Using the exercise files| 00:00 | If you are a monthly or an annual
subscriber to lynda.com, you won't have the
| | 00:03 | exercise files that accompany this
tutorial, but you can follow along with me.
| | 00:08 | Everything that's in the exercise files,
we'll create during the tutorials.
| | 00:11 | So as long as you continue to follow along,
your files will exactly mirror what is
| | 00:15 | in the exercise files. Remember that
you can pause at the movie or rewind if
| | 00:19 | you need more time to copy something down.
| | 00:22 | If you are a premium member of the
lynda.com Training Library or if you are
| | 00:25 | watching this tutorial on a disk, you
will have access to the exercise files
| | 00:29 | that are going to be used throughout
this title. The Exercise Files for this
| | 00:32 | title are arranged by chapter and by
movie and you can find the Exercise Files
| | 00:37 | that correspond to the movie you are
watching by first looking for the chapter
| | 00:40 | number and then the movie number.
| | 00:42 | In order to make use of the Exercise
Files, you want to first make sure that
| | 00:45 | you have PHP and MySQL successfully
installed and there's an appendix at the end of
| | 00:49 | the training if you need a refresher.
Once you are confident that you have
| | 00:52 | everything installed, then you will
want to move the folder back to the
| | 00:55 | Exercise Files into your site's directory.
| | 00:57 | On a Macintosh that's going to be
inside your Users directory and inside the
| | 01:01 | Sites folder. If you are on Windows,
you can move them into your Documents folder,
| | 01:06 | or the folder where you would
normally do your web development and then
| | 01:08 | you can simply drag the file in. On my
Mac, I'll Option+Drag to create a new copy.
| | 01:14 | Once it's copied, if you rename
the file so that you remove the chapter
| | 01:18 | number and the movie number, then your
files will be exactly the same as mine.
| | 01:22 | In many of the chapters, we're going to
be working with databases. In addition
| | 01:26 | to the exercise files that you will
drag in to your Sites directory and then
| | 01:29 | rename, they will also be an SQL
database file. This file can be loaded into
| | 01:36 | MySQL to put your database into the
same state as mine. If you don't already
| | 01:40 | have a database to load the file into,
you want to review the beginning of
| | 01:43 | Chapter 5, where we first create our
database and set up the necessary permissions.
| | 01:47 | Once you do that, you can either load
the file directly into MySQL by using a
| | 01:51 | tool such as phpMyAdmin or by going to
a command line and typing MySQL followed
| | 02:00 | by the name of the user who is
authorized to access the database,
| | 02:04 | their password, the name of the database
we want to use and then the less than sign
| | 02:09 | followed by the path to the exercise
file and you can either type out the full path
| | 02:13 | or you may be able to drag it
into the window. On a Mac, you are able to
| | 02:17 | just drag it in there and it puts
the whole path in there for you.
| | 02:20 | Once you've located the file that you
want to load into the database, simply
| | 02:23 | hit Return and it will update the
database with the instructions in that file.
| | 02:27 | Once you have the same files and the
same database, you will able to work right
| | 02:31 | along with me. Don't forget you can
also use the Exercise Files to check your work
| | 02:34 | as you go along.
| | Collapse this transcript |
|
|
1. Installation and Project SetupPHP and MySQL installation| 00:00 | Because this training tutorial is a
continuation of PHP and MySQL Essential
| | 00:04 | Training or because you already have
previous experience, you should already
| | 00:07 | have these two technologies installed
on your machine. If not, we have provided
| | 00:12 | an appendix that will help you to get
them installed or you can refer back to
| | 00:15 | the Essential Training.
| | 00:16 | The one footnote I want to make to
this though is just to make sure that
| | 00:20 | you are using PHP 5 or later. PHP 4 has
basically disappeared for all intents and
| | 00:25 | purposes. It's no longer being
developed. It's only being supported in the
| | 00:29 | smallest way and it does not have all
the features that we're going to be using
| | 00:33 | for object oriented programming.
| | 00:34 | So we really need to make sure that as
a minimum, we have PHP 5 installed and
| | 00:38 | we'll see how to do that when we set up
the project in the next movie. You can
| | 00:41 | also go to php.net and that will always
let you know what the latest version is
| | 00:46 | and give you links to get those downloaded.
| | Collapse this transcript |
| Project setup| 00:00 | You should have PHP and MySQL
installed at this point but there are couple of
| | 00:04 | housekeeping things that I want us to
take care of before we dive into PHP,
| | 00:07 | just to make sure that we're working
in the same sort of environment. Now
| | 00:10 | if you remember, in PHP Essential Training,
we created a folder that we called our
| | 00:14 | sandbox and that's where you put all of
these miscellaneous PHP exercise files
| | 00:18 | that we were creating and working with.
We'll do the same thing for this title.
| | 00:21 | On a Mac, those are going to be inside
your hard drive, inside the Users folder
| | 00:25 | and inside your name. In my case, it is
just Kevin and then inside that folder,
| | 00:31 | there will be a folder called Sites. Now,
on a PC, it will just be the root of
| | 00:34 | your web server and that's where you
will put all your files. On a Mac or a
| | 00:38 | UNIX system, you are going to put
those inside the User directory.
| | 00:40 | You will see that I have php_sandbox
here where I created those files before.
| | 00:46 | I'm going to create a new folder here,
just called btb for Beyond the Basics
| | 00:52 | sandbox and that's where I'll put all
these files. Now, there are two files
| | 00:56 | that I want us to grab out of the php_
sandbox that we were working with before.
| | 01:00 | The first of those is just basic.html.
So, if I open that up in TextMate,
| | 01:06 | you will see that it is just a real simple
HTML template. Your text editor may even
| | 01:10 | generate something like this for
you but this is good to have on hand.
| | 01:14 | I will drag that into btb_sandbox
and the second one, if we go down is
| | 01:19 | my_phpinfo.php. So, if we open that
one up, you will see that it is just
| | 01:25 | a real simple PHP info function that
will give us the configuration information
| | 01:30 | for PHP. It also has the nice side
effect of letting us know that PHP is
| | 01:35 | working, all right, because it's able to
run this PHP code. Now, you will notice
| | 01:39 | that there is the note there to
remind us that we should never include this
| | 01:42 | file on the production machine.
We don't want the public to have the
| | 01:45 | configuration info for our PHP.
This is only for development.
| | 01:48 | Now I'll take that file and I'll
actually just drag that to my Desktop here and
| | 01:52 | then go back up to drag it into btb_
sandbox. There we are. So now that I have
| | 01:58 | those two files in there, I'm ready to
locate them inside a web browser. So
| | 02:01 | I'm going to go down and open up Firefox
and the way we're going to locate it is
| | 02:06 | localhost. That's our local machine.
And then on a Mac, you are going to need
| | 02:11 | to put a Tilde and your user name.
For PC, you can leave that off, just localhost
| | 02:16 | and then the slash, and then
the folder name btb_sandbox and then
| | 02:22 | my_phpinfo.php.
| | 02:26 | Now if that comes up for you, then you
have successfully located the file in
| | 02:30 | the right place and PHP is running.
If not, you will need to troubleshoot it
| | 02:34 | and make sure that you have the files
where they need to be, that your web
| | 02:37 | server has started and that PHP is
running okay. If we get here, we know
| | 02:42 | we have got those things all working.
The web server, PHP, and we have successfully
| | 02:46 | found the right directory. Notice that
it tells us at the top it's PHP Version
| | 02:50 | 5.2.6 for me. You may have something
different than that. That's fine as long
| | 02:55 | as it is version 5 or later. Version 4
doesn't have all the features that
| | 02:59 | we're going to be using. So you want to make
sure that you are using version 5 or later.
| | 03:03 | The last thing that I want in this
to notice before we move on is this
| | 03:07 | Configuration File (php.ini) Path
and for me, it's in /etc. It may be
| | 03:13 | something different for you. That's
fine but this is the location of the
| | 03:17 | configuration file for PHP. If we want
to make changes to that file for any reason,
| | 03:22 | to change the different options,
that's where we're going to find the file
| | 03:25 | and we can edit that with a basic
text editor or through our command line
| | 03:29 | tools and we saw how to do that
previously, so I won't go over it again.
| | 03:31 | I just wanted you to take note of where
that file is in case you have forgotten
| | 03:35 | because it is not often that we edit it.
So now that we've successfully located that file,
| | 03:39 | we're going to be creating files in
our btb_sandbox where we can learn
| | 03:44 | different PHP techniques and we'll get
started with that in the next chapter.
| | Collapse this transcript |
|
|
2. Intermediate PHP TechniquesUsing variable variables| 00:00 | Before we dive into object oriented
programming and start working on a larger
| | 00:04 | project, I want to take a little bit
of time to visit some intermediate PHP
| | 00:07 | techniques that may fill in some of
the gaps in your knowledge or may prove
| | 00:11 | useful to you as we keep working.
The first one among these I want to look at is
| | 00:14 | variable variables. That is where
the variable name is determined by a
| | 00:19 | variable. Let's take a look.
| | 00:21 | So the first thing I'm going to do is
I'm just going to open up baisc.html.
| | 00:25 | I'm just going to do a Save As on this
file and save it as variable_variables.php
| | 00:35 | inside that btb_sandbox. Now I'll see
the file is right here and that's where
| | 00:39 | we'll be keeping all of the files that
we're working with. Now I'll go ahead and
| | 00:42 | just change the title to be Variable
Variables, just for reference. Then we can
| | 00:46 | put our PHP code here in this body block.
| | 00:50 | So we have talked about variables in
the past and you are familiar with using them.
| | 00:53 | Something like $a = "hello" or
we could have $hello = "Hello everyone."
| | 01:03 | We know how to do echo $a or echo $hello.
To make it nice and clean on the output,
| | 01:12 | I'll go ahead and put some <br/> tags
at the end of this and I'll do another one here.
| | 01:18 | So let's go ahead and load it up in a
web browser just as a simple starting point,
| | 01:22 | localhost, there we are. btb_sandbox
and then variable_variables.php. So there we are.
| | 01:33 | Nothing that we don't already
know how to do, but one of the
| | 01:36 | questions that often comes up from
students is what if we don't know
| | 01:40 | the variable name that we want to use?
What if it's dynamically computed?
| | 01:43 | How do we go ahead and evaluate that name
and have a dynamic variable name? So in other words,
| | 01:49 | we would not know hello;
instead we would have a string hello.
| | 01:53 | We would want to use that string to
return the value of the variable hello.
| | 01:58 | Well it's really easy to do. All we
have to do is echo $$a. So what this is
| | 02:05 | going to do is it's going to take
the value of $a and come up with the
| | 02:09 | string hello and then use that with
the second dollar sign to come up with
| | 02:14 | the value of hello up here. It works
exactly like you would think. Let me go ahead
| | 02:18 | and just put in another <br/> tag down
here and we can load that up. We can see
| | 02:24 | that that's true.
| | 02:25 | That's order is to being able to use
dynamic variables. You may not have a good
| | 02:29 | picture in your head of when this
kind of technique might be useful.
| | 02:32 | So I have made just a real simple example
that I want to show you. I have created a file
| | 02:36 | called seats.php. You don't need to
copy it down but you can. It's real simple.
| | 02:40 | It just simply takes a set of seats
and let's imagine it's a classroom and
| | 02:44 | the seats are labeled a, b, c, d and e.
There is a different student sitting in
| | 02:48 | each seat and we have
assigned those to a variable.
| | 02:50 | So then let's say maybe through a web
form I'm able to get together an array of
| | 02:56 | the seats that I want. So seat a,
seat c and seat e, are the students that
| | 03:00 | I want to reference or talk about or work
with. Those can brought in as strings,
| | 03:04 | stored in a database as strings, set in a
web form of strings. Then what we'll do is
| | 03:09 | we'll say well, for each student as
the variable seat, just a foreach loop,
| | 03:15 | take each one of those and do
this dynamic variable retrieval,
| | 03:18 | variable_variables.
| | 03:19 | So in this case, you can see that it
should return back to us the students
| | 03:23 | sitting in the seat a, sitting in seat
c and seat e. So if we save that,
| | 03:28 | if we come back over here and let's just
try it real quick, seats.php, you'll see
| | 03:32 | that's exactly what we get.
| | 03:34 | So it's a real simple example, but
you can see how this information here, right,
| | 03:38 | these items, could be pulled from
a database or sent in a URL or web form
| | 03:44 | and then used to reference something else.
So that's the kind of case where to use it.
| | 03:48 | Now there is one catch to this. There
is one thing that makes it tricky. I want
| | 03:52 | to make sure that I highlight it for
you. That is, if you think about the
| | 03:55 | syntax here, you have to wonder what
would it do if we had something that was
| | 04:00 | of this format? $$ and then the
variable name and then the item that we want to
| | 04:06 | reference inside an array. So in this
case, we would be looking for the first
| | 04:10 | item of an array. So with this syntax,
would it mean to, number 1, get the
| | 04:15 | first element of the array and then
evaluate that answer dynamically?
| | 04:20 | Or should it evaluate var dynamically and
then look for the first element of that array?
| | 04:26 | So it's not clear which one of these we
should do first. This part is clear but
| | 04:29 | then it's not clear for you should
do the 1 before the dollar sign or
| | 04:33 | the dollar sign before the 1. So in order
to make this unambiguous and to make it clear,
| | 04:37 | what we do is use the curly
braces. So in the first case, we would put
| | 04:43 | the curly braces around the $var and the 1.
In the second case, we would just put it
| | 04:49 | around the first variable, to let it
know that it should pull that in first,
| | 04:53 | then evaluate the first element from there.
| | 04:57 | So it works a lot like parenthesis do
in mathematical operations, telling us
| | 05:01 | which one we want to do first. We're
just using curly braces. That's only when
| | 05:04 | we're really working with arrays that
it becomes a problem. Most times it won't
| | 05:07 | come up, but I just want to make sure
that I at least gave you that footnote,
| | 05:10 | so that you don't run into problems with it.
| | 05:12 | That's all there is to using variable
variables. Let's take a look in the next
| | 05:15 | movie at some more functions that we
can use this time working with arrays.
| | Collapse this transcript |
| Applying more array functions| 00:00 | In this movie we're going to take a
look at a couple of array functions that
| | 00:02 | will allow us to put elements into and
pull elements out of arrays, besides the
| | 00:07 | techniques that we have already learned
in the past. I think these are going to
| | 00:10 | be really useful for you.
| | 00:11 | The first thing I want to do is go and
open up that basic.html file again, and
| | 00:15 | I'm just going to do another Save As on
it. This time we're just going to call
| | 00:19 | it array_functions, and be
sure to change it to .php.
| | 00:24 | Then I'll change the title as well,
Array Functions. Then we'll open up some
| | 00:30 | php 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:42 | Now, you remember that instead of
echoing back arrays, it's really useful if
| | 00:46 | we can use print_r to be able to see
them instead, and that just gives us some
| | 00:50 | nice formatting for those.
| | 00:52 | But then right after it, I'll do an
echo of two br tags, just so that we can
| | 00:58 | separate it from everything
that's going to come after it.
| | 01:01 | Now, the first technique I want to look
at for pulling element out of an array
| | 01:04 | is called Shift. So array_shift is
the function name, and it will shift the
| | 01:09 | first element out of an array and
return it. So in the case of $a =
| | 01:15 | array_shift($numbers); that I have
there, you can almost imagine the first
| | 01:19 | element being shifted out of the
numbers array and being pushed and sent into
| | 01:24 | that a. So it's shifting it from
numbers into the variable that we have there.
| | 01:30 | Now, we don't have to catch that, we
could just run array_shift without taking
| | 01:34 | that value and putting it anywhere and
it will just continue to pull that first
| | 01:37 | value out of it. That's what its
doing really is pulling that first element
| | 01:41 | out, whether we catch it in the
variable or not is up to us. But we can go
| | 01:44 | ahead and just do echo "a:" and then
we'll put in the $a and put another <br/>
| | 01:53 | tag at the end of it. Then let's go
ahead, just for good measure, and let's
| | 01:58 | take a look at what numbers is again.
| | 02:00 | We will Save that. We'll go back into
Firefox and we'll load up our sandbox
| | 02:05 | page/array_functions.php. There we go.
So you will see that all the elements
| | 02:11 | have just simply shifted over, so
that now the array is only 2,3,4,5,6.
| | 02:17 | The 1 got pulled off and
put into the variable of $a.
| | 02:20 | Now, we can do the reverse of this as
well, which is Unshift. So here I'm going
| | 02:26 | to go ahead and just Paste it in there
so you can see it. It's the same thing.
| | 02:29 | What we're going to do is call array_
unshift($numbers); and provide it with the
| | 02:34 | element that we want it to unshift to
do the reverse. So in this case it will
| | 02:39 | put it back or push it onto the front of it.
| | 02:42 | Now, I'm also catching what that
returns in the variable b. What it's going to
| | 02:47 | return is the element count. It's going
to let us know how many elements are in
| | 02:51 | there altogether.
| | 02:52 | This might be useful for you or not.
Again, you don't have to catch that value
| | 02:56 | in a variable if you don't want to,
but we can do the same thing and take a
| | 02:59 | look, just to see the difference.
Sure enough, you will see that it has six
| | 03:03 | elements in the array now. The first
one is now first. It pushed it back onto
| | 03:09 | the front of that.
| | 03:09 | Now, when I was talking about these, I
talked about unshifting as being pushing
| | 03:14 | an element onto the front of it and
shifting as popping an element out of it.
| | 03:18 | It turns out that there are two more
functions that we can use that are called
| | 03:23 | Pop and Push. So I'm just
going to put those down here.
| | 03:26 | I have got an hr tag that I just
dropped in at the top to just separate the
| | 03:30 | two. Here is unshift up here at the top.
Then I have got my new code, array_pop
| | 03:34 | and array_push, and they work exactly
the same, except that it pops the last
| | 03:40 | element out of an array, not the first
element, the last element, and returns
| | 03:44 | it. Push does the same thing as
unshift, but instead of doing it to the
| | 03:48 | beginning of the array, it pushes
the element onto the end of an array.
| | 03:52 | We can see this, if we save our new
file and we reload it in the browser. We'll
| | 03:56 | now see, in this example, we pulled the
1 out and replaced it with first. Then
| | 04:03 | first still persists all the way
through here, it never gets pulled out. But
| | 04:06 | the last element here, which was 6,
gets removed and assigned to a. Then we put
| | 04:13 | in the word last, we'll push that
onto the end. So Shift and Unshift at the
| | 04:17 | beginning, Push and Pop at the end. So
those are going to be the four that are
| | 04:21 | going to allow us to put things into
our array at the beginning and the end.
| | 04:25 | Now, we know we also have ways of
assigning a value directly to a certain
| | 04:29 | position, we saw those in the Essential
Training, but this will allow us to say
| | 04:32 | whatever that value is at the end,
not only do I want to retrieve it, but I
| | 04:36 | want to take it out of the array at
the same time. That's the thing that
| | 04:40 | we couldn't do before. It both gives us
the value and takes it out of the array at
| | 04:45 | the same time. So those are going to
be really useful for you, I think, when
| | 04:48 | working with arrays.
| | 04:50 | Now, I want to encourage you to take
time to go through the PHP website,
| | 04:54 | php.net, and look at the other
functions that are available. array_shift is
| | 04:58 | right here, but you will see there
are a lot of array functions here that
| | 05:01 | you can use, and it's worth seeing how
arrays can be powerful for you, because
| | 05:06 | there are so many functions and so
many different ways you can use them.
| | 05:09 | I am not going to try and cover them
all, because a lot of them are for rare
| | 05:11 | cases, but I think that you might find
array_flip is something that helps you
| | 05:16 | out of a jam that you are in, or array_
keys gives you what you are looking for.
| | 05:20 | So take some time and explore all of
these functions, build yourself your own
| | 05:24 | page, start playing with them,
and see what they can do for you.
| | 05:27 | But we're going to move on and we're
going to take a look at dates and times
| | 05:30 | in the next movie.
| | Collapse this transcript |
| Building dates and times: Epoch/Unix| 00:00 | One of the areas that perplexes a lot
of beginning developers is working with
| | 00:04 | dates and times. That's partly because
there are a lot of different ways to do
| | 00:09 | it and there are a lot of restrictions
that depend on what kind of operating
| | 00:12 | system you have, what kind of database
you are using, and things like that that
| | 00:16 | just make it into a quagmire
that's hard to wade through.
| | 00:19 | So I'm going to give you some of the
basics, some of the essential concepts
| | 00:22 | behind it, and then you will have to
take a look at your system and see what
| | 00:26 | works for you and do some research on
ways to work around it, but this will at
| | 00:30 | least give you the fundamentals.
| | 00:32 | The first thing that we need to talk
about is going to be Epoch time or the
| | 00:36 | Unix timestamp. These are the same
things, and if time sets the computer
| | 00:40 | epoch_began. So basically that's the
time that Unix is going to use for its
| | 00:45 | timestamp. Essentially it's the
number of seconds that have elapsed since
| | 00:49 | January 1, 1970 at midnight. That is
the beginning of the computer epoch
| | 00:55 | according to the Unix timestamp.
| | 00:57 | Since Unix is a file system, it must
have seem like common sense to the people
| | 01:01 | developing it that a file could not
be created before January 1, 1970. The
| | 01:07 | problem comes in when we start using
these dates for things besides just files
| | 01:10 | that are being created on the computer
and start using them to keep track of
| | 01:13 | birthdays and other calculations, then
we might have dates that go into the past.
| | 01:18 | Now, if we have a 32 bit system, we're
able to use dates from December 1902 to
| | 01:23 | January 2037. 1970+67 years to get to
January 2037, or 67 years in the past to
| | 01:33 | get to December 1902. We do that by
having a negative number. So we can count
| | 01:38 | time forwards and backwards in negative numbers.
| | 01:40 | But that also limits us. We still
can't talk about some birthdays.
| | 01:44 | We can't talk about dates that happened in
history. We can't talk about future, social
| | 01:49 | security payments, and things like that
that might happen past 2037. So that's
| | 01:53 | still a pretty limited range.
| | 01:55 | So ultimately, what I think is going
to happen is most systems will end up
| | 01:58 | going to a 64 bit system of counting,
because that will last for billions of
| | 02:02 | years and that will take care of all
of our needs, but we haven't done that yet.
| | 02:06 | So on your system, you may be limited
to 1902-2037, and if you are on a Windows
| | 02:12 | machine or maybe some of the older
Linux distributions, even dates prior to
| | 02:16 | 1970 might give you a problem. I think
I ran into that with the IIS database.
| | 02:21 | It had problems with dates before
1970, and that's because Windows does.
| | 02:25 | If you ran into one of those problems,
what are you going to do? Well, there
| | 02:27 | are many choices and it depends on
your needs. You can store the date as a
| | 02:31 | string, you can store the year
separately from the date, or you could read up
| | 02:35 | on one of the many hacks that are
out there on ways to get around it. The
| | 02:38 | php.net website is full of a lot of those.
| | 02:41 | But for the purposes of this tutorial
I don't want to focus on how you are
| | 02:44 | going to work around the limitations
of the computer you are working with,
| | 02:47 | because you may get a shiny new
compute tomorrow that handles all of it fine,
| | 02:51 | instead I want to talk about the
fundamental principles that we're going to be
| | 02:53 | working with to create a Unix timestamp.
| | 02:56 | There are three ways that I want to
look at to do that. The first is just time.
| | 02:59 | time with no arguments,
just have the parenthesis and that will
| | 03:04 | return the current time. Remember
that's the number of seconds since 1970.
| | 03:10 | So that's the Unix timestamp.
| | 03:11 | Now, the second is that we can make time,
mktime and we just need to provide
| | 03:17 | it the number of hours, minutes,
seconds, and then month, day, and year.
| | 03:22 | It will come back to us with a Unix
timestamp, the number of seconds since 1970.
| | 03:27 | Now, notice the order there, it gets a
little confusing for some people. It has
| | 03:30 | the time first, hour, minute, second,
and then it has month, day, year, which
| | 03:35 | is sort of the American way, instead of
day, month, year, like they do in other
| | 03:38 | countries. So they are not in sort of
ascending order or anything like that,
| | 03:43 | it's a little bit of a jumble, but
that's the order it's going to be. An hour,
| | 03:45 | minute, second, month, day, year.
| | 03:47 | The last is string to time, strtotime,
and then we provide any string to that
| | 03:54 | function and it will return a Unix
timestamp to us, doing the best it can to
| | 03:58 | generate that timestamp based on
whatever is in that string. We'll take a look
| | 04:02 | at that, it's a pretty neat little function.
| | 04:04 | So I'm going to open back up array_
functions, and I'm just going to do a Save
| | 04:07 | As on that file, and I'm going to
call this date_time_unix.php, just to
| | 04:13 | remember, because we're going to take a
look at some other date, time features later.
| | 04:15 | I'm going to take out all of
this and I'm going to call it Dates and
| | 04:20 | Times: Unix.
| | 04:22 | Now, the first way that we're going to
make Unix time we said was just with the
| | 04:27 | simple Time command. So we'll do that
with just echo time;. We'll save that,
| | 04:32 | and let's open that up in our browser
and see what we get back. So we'll just
| | 04:35 | open up a new window and we'll go back
to our sandbox/date_time_unix.php.
| | 04:44 | There we go. That's how many seconds have
elapsed. If we reload it, we can see all
| | 04:48 | the seconds as they continue to count.
| | 04:51 | Now, we'll learn how to format that
into something that looks nicer a little
| | 04:54 | later. What we're interested right
now is just getting that Unix timestamp,
| | 04:59 | because once we have a Unix timestamp,
we can start to compare different
| | 05:03 | timestamps. We can see when something
happened 5 minutes ago, 10 minutes ago,
| | 05:06 | by comparing the current timestamp
with the timestamp that we have stored,
| | 05:10 | let's say, in a database or in
a file or something like that.
| | 05:13 | The second way we saw that we could
make a timestamp is with mktime, and
| | 05:19 | you will remember that I told you that
we have to provide the number of arguments here.
| | 05:22 | We can do those as variables or
just simply integers. So the first of
| | 05:26 | those is going to be the hour, let's
say 2, and the minute 30, and the seconds
| | 05:33 | we'll make 45. Then we need to put in
the month and the date and the year, and
| | 05:40 | I'll put in 2009. Semicolon there and
let's, just for good measure, let's put
| | 05:46 | in <br/> tag at the end of this just so
it will be on a new line. Let's reload it.
| | 05:52 | There we go.
| | 05:53 | So now you see the difference
between the current time and the number of
| | 05:57 | seconds there, and this date in the
future for 2:30:45 on October 1, 2009.
| | 06:04 | We can actually subtract the two and
find out how many seconds there are in
| | 06:08 | between and then convert that
to a number of days and so on.
| | 06:11 | Now, one note is that if you give something
invalid to mktime, it will return false.
| | 06:16 | So if you try to tell it the
date was February 30, that's an invalid
| | 06:21 | date and it would return false.
| | 06:23 | Now, there is also another way that we
can check whether dates are true that's
| | 06:26 | worth mentioning, and that is with checkdate.
| | 06:30 | If we say, for example, echo checkdate
(12, 31, 2000), and then we'll ask it to
| | 06:39 | return 'true', if that's a true date,
or 'false', if it's not. We can do the
| | 06:46 | same thing again. Let's go ahead and put
our brs in here, just to make it nice and clean,
| | 06:51 | but this time let's ask it for
February 31. Let's see whether that's a date.
| | 06:56 | So if we come back and we reload those
pages, you will see that the first one
| | 06:59 | is a date and the second one is not a
date. So checkdate is also a helpful way
| | 07:03 | to check whether a date is there or not.
| | 07:05 | Last of all, I want us to take a
look at that really cool function, the
| | 07:09 | strtotime. So let's say $unix_
timestamp = strtotime, and then we can put in
| | 07:19 | a string that designates whatever
time we would like. Now, this is the cool
| | 07:23 | part. 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:34 | Let's load that up and see what we have
got. So there we are. Notice the times
| | 07:38 | are the same at the top and the bottom.
time("now"), there is no difference
| | 07:42 | whatsoever. I can also put in something
like "15 September 2004", and then come
| | 07:50 | back. There is the date stamp for that.
I could also do "September 15 2004",
| | 07:56 | and you will see I get the same date
stamp. So it's able to interpret these
| | 08:02 | different ones.
| | 08:03 | Let's try "+1 day". That's tomorrow,
or we can say something like "last Monday".
| | 08:11 | So there are a lot of these
different things that we can do, that
| | 08:16 | we can pass in as a string and it's able
to interpret what we mean. Now, it isn't
| | 08:20 | always 100% successful, you will have
to play around and try it out a little bit,
| | 08:24 | but it does a pretty good job of parsing
it out and figuring out what you mean and
| | 08:28 | turning that into a Unix timestamp.
So keep that in your back pocket
| | 08:31 | because that's a really useful tool.
| | 08:33 | Now that we know how to make Unix
timestamps, in the next movie we'll talk
| | 08:37 | about how to make those into something
that's human readable, how to go from a
| | 08:41 | timestamp 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:00 | In this movie, we're going to
continue looking at dates and times.
| | 00:03 | In the last movie we saw how to build a Unix
timestamp, and in this movie I want us to take
| | 00:07 | a look at how we can format that Unix timestamp.
| | 00:09 | There are two functions that are
going to allow us to do that. The first
| | 00:12 | function is date and the second is
strf time. Now, you can either pronounce
| | 00:18 | that string for time, string format
time, but the idea is that we're taking a
| | 00:23 | timestamp and turning it into a string.
So in both cases we're going to be
| | 00:27 | formatting a Unix timestamp into
something that's human-readable, like November
| | 00:31 | 13, 2005, instead of however many
seconds it has been since 1970.
| | 00:36 | That's not very user-friendly.
| | 00:38 | You will see that each of these
functions takes a timestamp as a second
| | 00:41 | argument. That timestamp is just a
simple Unix timestamp, we can take any
| | 00:45 | timestamp we have created and drop
it into that second argument. It's the
| | 00:48 | format that's the tricky part and that
we're going to have to learn more about.
| | 00:51 | In fact, the functions may look
identical but what differentiates them is the
| | 00:55 | format. Each function has its own format
rules. Let's take a look at date first.
| | 01:00 | The easiest way to show you the
formatting options for date is to take a look
| | 01:03 | at the http://www.php.net page for
date. Go to http://www.php.net and do a
| | 01:07 | search for date and you will get this
page. Here are the different formats for
| | 01:11 | the output string. Scroll down.
| | 01:13 | Notice the format characters over here,
d, D, j, and so on, and it tells you
| | 01:20 | what each code does. So, for example,
d is the day of the month, two digits
| | 01:24 | with leading zeros, such as 01 to 31.
You will notice that j is also the day of
| | 01:31 | the month, but without leading zeros, 1 to 31.
D is a textual representation of a day,
| | 01:37 | the three letters, Monday through Sunday,
so Wed for Wednesday, for example.
| | 01:41 | Now, we can scroll down a bit further
on the page to see how these strings are
| | 01:45 | used. The format is a simple
string but with the format characters as
| | 01:49 | placeholders for each part of the date.
When the date function is called,
| | 01:53 | it will replace the format code
placeholders with the actual data.
| | 01:56 | So for example, this format string
here will return the line right above it.
| | 02:02 | Monday 8th of August 2005 and then the time.
| | 02:06 | Now, in this example they are not
passing in a timestamp, so it defaults to the
| | 02:08 | current time. But in the example below
that, you can see that they do pass in
| | 02:13 | the timestamp as a second argument.
They build the timestamp using mktime and
| | 02:16 | then pass it in.
| | 02:17 | Notice also that the format code that
they are using in that second one is just
| | 02:21 | simply an L, and that's it. If we go
and look at L, you will see what it does
| | 02:24 | is it returns the day of the week. So
this will tell you what day of the week
| | 02:29 | July 1t 2000 is. That's a nice little
trick. Not only are we able to format the
| | 02:34 | date in something human-readable,
we're actually able to find out some
| | 02:37 | information about the calendar as well.
| | 02:39 | Now personally, I don't use date and I
would recommend that you also use string
| | 02:43 | for time instead. The reason why I like
it better is that its part of the Unix
| | 02:47 | Open Standard and it's used by many
programming languages, besides PHP, and has
| | 02:51 | support for formatting dates in foreign
languages as well. So let's take a look
| | 02:55 | at the string for time format codes to see
how they are different from the ones for date.
| | 02:58 | So for example, if we look here at %d,
you will see that there is a % in front
| | 03:02 | to it, first of all. The % helps make
it clear that this is a format code. So
| | 03:07 | all the string for time ones are
going to be proceeded by % sign before the
| | 03:10 | code. So essentially %d does the same
thing that d did in the date function.
| | 03:16 | But now take a look at %D. You will
see that this is different. Instead of
| | 03:21 | being the three-letter code for the
day of the week, it's going to be a
| | 03:24 | shortcut for the month, day, and year
as numbers with slashes in between them.
| | 03:29 | Instead, if we look at %a up here, you
will see that that is the abbreviated
| | 03:33 | weekday name. So that's how we get
that same functionality we had before.
| | 03:36 | So some of them are going to be the
same. %m for example down here, the month
| | 03:41 | as a decimal number. That's the same.
But %M and other ones like that are not.
| | 03:45 | So there is a lot of differences. So
you really have to learn each set of code
| | 03:48 | separately, and that's why I think you
ought to pick one and stick with it, and
| | 03:51 | I recommend you go with the
string for time (strftime).
| | 03:53 | Now obviously, this list here of
codes on the string for time is a
| | 03:57 | comprehensive list, and you may want
to copy down the ones that you are going
| | 04:00 | to use most often and make yourself a
little cheat sheet. But you will also get
| | 04:03 | familiar pretty quickly with them and
you will be able to remember the ones
| | 04:06 | when you need it.
| | 04:07 | So let's try this out now. I have
still got my old window open for
| | 04:11 | date_time_unix. Let's go ahead and do
File > Save As on that, and we'll call
| | 04:17 | this one instead date_time_format.php,
and I'll just change it up here to say Formatting,
| | 04:23 | and then we'll go ahead and clear up all
the PHP we had there so we can start fresh.
| | 04:29 | So the first thing I'll do is I'll just
build a real simple timestamp with the
| | 04:32 | current time. And we know how to do
that with just time. Then let's make
| | 04:36 | ourselves echo back the result of
strftime, and we'll say, "The date today is"
| | 04:44 | and let's put in our format code, so %m.
So the % sign lets it know it's a code
| | 04:49 | for strftime, and then the m tells
it that it will be the numbers for the
| | 04:53 | month, and then we'll have %d/%y. Then
last of all we need to pass in of course
| | 05:00 | our timestamp.
| | 05:02 | Let's go back over to our browser and
try that out. Instead of loading up Unix,
| | 05:07 | I load up format.php. There you go. So
today is November 1 2008. Now, today is
| | 05:13 | not actually November 1 for me.
Instead I set my system clock to that time so
| | 05:17 | that I could show you something.
| | 05:18 | Now, earlier I pointed out the reasons
why I like strftime better than date.
| | 05:22 | There is one feature that date has that
strftime doesn't. Date has options for
| | 05:26 | leaving off the leading zeros before
a month or a day number. Notice here I
| | 05:31 | have got the 01. That's the leading
zero that I'm talking about in front of it.
| | 05:34 | We kept the option to leave that off
in date and it could just simply be
| | 05:38 | 11/1/08. The same thing would be true
if we were talking about January, string
| | 05:43 | for time would print as 01, whereas in
date we have the option of leaving the
| | 05:48 | leading zero off.
| | 05:49 | A lot of times we're going to want to
get rid of those leading zeros. So I'm
| | 05:52 | going to show you how you can do that
by writing yourself a helper function.
| | 05:55 | It's a little bit of a hack but it is effective.
| | 05:57 | So what we'll do here is we'll just
take this line and we'll copy it down here,
| | 06:03 | and instead of just sending in the
formatting, we're going to put an asterisk
| | 06:06 | in front of each of these two. Those
are the two places where a zero may show
| | 06:11 | up. So we're sort of marking the
position where we want to watch for a zero,
| | 06:15 | and we're doing that with this asterisk.
Now, you can use any character you want.
| | 06:18 | I picked the asterisk because
it's something that I don't use very often
| | 06:22 | when I'm formatting this kind of date,
but you could easily use a different character
| | 06:25 | if you needed the
asterisk for another reason.
| | 06:28 | So now let's write ourselves a helper
function, function strip_zeros_from_date,
| | 06:36 | and then we'll pass in $marked_string=,
and there we go, we'll pass in a empty
| | 06:44 | string by default. The first step is
that we're going to remove the marked
| | 06:49 | zeros. 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:03 | we find it, eliminate both, get them
both out of there. Then we'll just need to
| | 07:08 | pass in the marked_string so
it knows what to search through.
| | 07:11 | Then once we do that, the last step
is we'll remove any remaining marks,
| | 07:19 | because we don't want to have to deal
with a case where we have something like
| | 07:22 | December, which would not have a
leading zero, and so we would still have that
| | 07:25 | asterisk sitting there
because it didn't get removed.
| | 07:27 | So we'll then do another step, $
cleaned_string =, and we'll do another
| | 07:32 | str_replace. But this time we're going
to be looking for any asterisk that's
| | 07:36 | still left around and we'll replace
that with nothing, and we'll do that to our
| | 07:40 | no_zeros string. Finally,
return back that cleaned value.
| | 07:48 | So there we go. Now we have a function
that should work for us. Let's just move
| | 07:51 | this strftime down below the function
so that it's defined. We'll just put it
| | 07:56 | around the whole thing. There we go.
I'll save it, and let's come back over.
| | 08:01 | Let's try it out.
| | 08:02 | There we are. It didn't put a br tag
in there but you can see this one does
| | 08:05 | have the 01. This one did remove the 01.
| | 08:08 | So most of my PHP projects I go ahead
and just put it in a function like this
| | 08:13 | that will help me to use strftime and
to be able to get rid of those zeros, and
| | 08:17 | I think it might be helpful to you too.
| | 08:18 | The very last thing I want to show you
here is that I can also format strings
| | 08:22 | suitable for storage in MySQL. A
lot of people wonder how you do this
| | 08:26 | conversion. You don't want to just pass
in a Unix timestamp to MySQL; you want
| | 08:30 | to format it to something that MySQL can
understand. Luckily it's very, very easy to do.
| | 08:36 | Let'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:48 | Then what we want to get is $mysql_
datetime, and the way we're going to do that
| | 08:53 | is using that strftime function and
we're going to put in the following
| | 08:57 | formatting code. %Y, that's the year
with all four digits, and then %m, %d,
| | 09:05 | then a space, %H for the hour, %M for
the minute, and %S for the second. There
| | 09:14 | we go, and then of course we'll want to
pass in that time we were just working
| | 09:18 | with. So we could pass in any timestamp,
and we're going to have it output with
| | 09:21 | this formatting. That will go into
this mysql_datetime. Of course, if we want
| | 09:25 | to see the results of that, then we'll
just need to do an echo on it. There we go.
| | 09:29 | So we'll come back and there we are.
That's the format that MySQL understands.
| | 09:36 | So go ahead and write down those
formatting codes. Make sure that you keep them
| | 09:40 | handy for working with MySQL. But you
also may want to just make a copy of this
| | 09:45 | here, just to show you what the result
should be, in case you end up using date
| | 09:49 | or some other system, whatever, this
is the format that MySQL wants for date,
| | 09:53 | time fields. Now, if is the date field,
it will just be the date part of that,
| | 09:56 | but this is the format it's going to use.
| | 09:58 | So now that we have learned to work
with and format the dates and times,
| | 10:01 | we'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:00 | In this movie we're going to take a
lok at how we can retrieve and work with
| | 00:03 | server and request variables. Now, we
have already seen some superglobals that
| | 00:07 | we can work with. We saw Get, Post,
Cookie, and Session. Well, there is one
| | 00:11 | other one that I want to introduce
you to, and that is Server. That's where
| | 00:15 | we're going to be able to find all of
these server and request variables, is
| | 00:19 | inside the superglobal for Server.
| | 00:21 | So what we're going to do is ask that
superglobal to return a value to us for
| | 00:26 | various information, like the server
name or the remote IP address that made
| | 00:31 | the request for this webpage. A lot of
times we'll want to keep track of that
| | 00:35 | to know where the request came from,
what the user's IP address is. We can do
| | 00:39 | that using the Server superglobal.
| | 00:41 | Let's try it out and see some of the
things we can ask it for. I'm going to
| | 00:45 | open up basic.html and I'm just going
to do a Save As on it, and we'll call it
| | 00:51 | server_variables.php, and put it in
our btb_sandbox, and Server Variables.
| | 01:00 | Now, the first two that we'll take a
look at will just be simply looking at
| | 01:04 | information about the server that
we're on. We can ask for our server's name,
| | 01:09 | for our server's address, and for its
port. Let's try those out and see what
| | 01:13 | we get back and think about how
you might use that information.
| | 01:16 | We will open up Firefox, and instead of
going to date_time, we're now going to
| | 01:21 | go to server_variables.php. So there
is the information that I have for my server.
| | 01:28 | Now, once you install this on a
production machine, probably your server name
| | 01:31 | will change, the port, the address,
those things will all change. Because I'm
| | 01:34 | using local host, it goes ahead and
resolves the server name to being local
| | 01:38 | host and my IP address is
just simply listed as one.
| | 01:40 | There are a few other things we can
ask for. We can ask it for the document
| | 01:46 | root on our server, where all our
files are located. We can also ask it for
| | 01:51 | details about the page that we're
working with. So here are some page details,
| | 01:55 | PHP_SELF. That's a very useful
way to find out what page this is.
| | 02:00 | server_variables page, or SCRIPT_
FILENAME, we can also pull that back.
| | 02:05 | Let's take a look at those.
| | 02:06 | I will save that file. Let's just
reload over here, save the file. There we go.
| | 02:13 | Reload it. So you will see my DOCUMENT_
ROOT, it tells me where the documents
| | 02:16 | are located. Then the Page details,
it tells me the path to get to the page
| | 02:21 | that it's actually executing. Then the
SCRIPT_FILENAME, you will notice, gives
| | 02:24 | me the same thing, but it gives me
from the root of the user's directory.
| | 02:29 | PHP_SELF is what's being typed into
the URL bar that's up here. The other one
| | 02:35 | is actually the path on the file system.
That's the SCRIPT_FILENAME. So notice
| | 02:39 | the difference between those two and
make sure you use the right one in each context.
| | 02:42 | If we want to redirect someone to a
URL or something, we would use PHP_SELF.
| | 02:47 | But if we're trying to locate a file
to include or require into our script,
| | 02:51 | then we might want to use something
like SCRIPT_FILENAME or our DOCUMENT_ROOT,
| | 02:55 | for example.
| | 02:56 | Now, notice that DOCUMENT_ROOT here is
actually not my user directory. That's
| | 02:59 | because of the way that Apache is set
up on a Mac system, so that my actual
| | 03:03 | root 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:11 | to use this Tilde in my user name.
| | 03:14 | Then perhaps most interesting to us,
we can find out information about the
| | 03:18 | request that comes in. So we'll switch
back over here and we can get details
| | 03:23 | with Request. We can get the
remote address that's asking for it. The
| | 03:27 | REMOTE_PORT, the URI that they ask
for, the QUERY_STRING, if they ask for
| | 03:31 | anything after the URL, the time it was
made, the REFERER. That's who referred
| | 03:36 | them to our website and that's really
useful for keeping track of links and
| | 03:39 | finding out did someone get to us by
clicking on a link on Google, for example,
| | 03:43 | or did they click on a link at Yahoo!
and that's how they found us. Then an
| | 03:46 | USER_AGENT, which is what browser
they are using. So those are great for
| | 03:49 | statistics and server tracking and
that kind of thing. So I'll save that.
| | 03:53 | We will come back and we'll just do a
reload. Now, of course my remote address,
| | 03:57 | since I'm doing it from the same server,
is just going be 1, but if we were to
| | 04:00 | put this up on a server somewhere,
then it would obviously pick up my IP address.
| | 04:05 | Now, you notice that the QUERY_STRING
is blank, let's go ahead and just put in
| | 04:08 | something here. Let's say q=1&n=2.
You will notice that now it pulls in the
| | 04:18 | elements in that query string and we're
able to then work with those and parse
| | 04:22 | those if we need to.
| | 04:23 | Now, we also have access to those
through the get superglobal, those will be
| | 04:27 | put there for us already, and that's
basically what's its doing is taking query
| | 04:30 | string and parsing it for us.
But if we need a direct access to it or
| | 04:34 | if we wanted to store in the database
and keep track of it or something,
| | 04:37 | we could also do that by just
looking at the query string.
| | 04:39 | Now, there are a lot of other server variables.
I think these are the most useful ones.
| | 04:43 | If you want to go to the php.net
website, it's a little tricky to find,
| | 04:47 | but php.net/manual/en/reserved.
variables.server.php and that will give you
| | 04:57 | all of those server variables that you
could have access to and you can look
| | 05:00 | and see if there are any others
that sound interesting to you,
| | 05:02 | anything you want to play with, but I really
think that the main ones are the ones that
| | 05:06 | we just took a look at.
| | 05:07 | There is one more thing that I want
to caution you about. There is also a
| | 05:09 | superglobal called Request. Don't use
Request. When you are trying to get those
| | 05:14 | request variables, you want to get them
from the Server superglobal. Request is
| | 05:19 | a superglobal that basically just
contains all of those Post and Get values
| | 05:23 | that we already have access to
through Post and Get, so it's a little bit
| | 05:27 | redundant. If you want to find out
the remote address of the request,
| | 05:31 | the REQUEST_URI, do that through the Server
variable, not through the Request superglobal.
| | Collapse this transcript |
| Establishing global and static variable scope| 00:00 | Now that you are not a beginner anymore,
we need to talk about variable scope a
| | 00:03 | little bit further, and specifically
talk about global and static variables and
| | 00:07 | what those can mean for us and do
for us. We saw global briefly in the
| | 00:11 | Essential Training, but I want to go
into it again here and expand on it a bit
| | 00:15 | to make sure that you
understand what's going on.
| | 00:16 | I am going to open up that basic.html
again and just do another Save As on it,
| | 00:21 | and we'll call this one
variable_scope.php. Variable Scope.
| | 00:36 | We talked about local and global
variables in the previous training.
| | 00:39 | Just to refresh your memory, variables that
are declared inside the PHP document are in
| | 00:44 | the global scope. So if I just start
declaring something like var = 1,
| | 00:49 | that is in the global scope.
| | 00:51 | Variables declared inside a function
have a local scope. So if I say, for
| | 00:56 | example, function test1, and we'll go
ahead and just declare a variable inside
| | 01:03 | there, var = 2, and that has a local
scope, its local to that function. We can
| | 01:10 | test this out by just having it echo
out those two values for us. So var, and
| | 01:15 | let's have it do br for us. We'll take
the same line. We'll just put it down
| | 01:21 | here. But we'll also need to, of
course, call the function, test1.
| | 01:29 | So if we try that out in our browser
and let's go to variable_scope. It figured
| | 01:38 | up the PHP for me, .php, there it goes.
You notice the first time the value is
| | 01:43 | 2 and second time its 1. So even
though we set the variable to 1,
| | 01:48 | then we defined our function, which doesn't
actually do anything, doesn't execute anything.
| | 01:52 | Then we execute the function here,
which does set variable equal to 2,
| | 01:56 | and we echo it out. That's first
two we're seeing, but then when it comes
| | 02:00 | back and it echoes it again, it is
echoing the variable that's in the global
| | 02:04 | scope. So study that a little bit and
make sure you understand the difference
| | 02:07 | between local and global.
| | 02:09 | Now, we saw though in the Essential
Training that we could also do it another
| | 02:14 | way, so that we could have access
to that global value inside our local
| | 02:19 | function. I'll just take the same
thing again and we'll come down here. Of
| | 02:25 | course, I'll need to make it test2
so that we don't conflict with the
| | 02:28 | previously defined function. But this
time the one difference I'm going to do
| | 02:32 | is I'm going to call global and var.
| | 02:36 | So what that does is it says, hey,
you know that var and the global scope>
| | 02:41 | That's what I mean when I talk about var.
All references from var, from here on
| | 02:44 | out, I'm talking about that thing. It's
like importing it into the local scope,
| | 02:50 | but it retains it. So it just pulls
it in so that we can work with it as a
| | 02:53 | reference almost.
| | 02:54 | So let's try that. Let's go back
and let's set up our page again.
| | 02:57 | Now you notice that var did change the
second time. So this assignment here, var 2, did
| | 03:03 | take place to only the global scope.
It brought in the global to the local,
| | 03:08 | made the assignment, and
that assignment stuck around.
| | 03:11 | So again, study those two examples and
make sure you understand what global is
| | 03:15 | and why we use that global declaration
before our variable to let it know that
| | 03:20 | we want to use the global value.
| | 03:21 | Now, the main reason I wanted to go
over this and make sure that you understand
| | 03:25 | it, it's not just so that you are
comfortable in using it, but also because it
| | 03:28 | leads us into talking about static
variables. A static variable is a local
| | 03:33 | variable to a function, but with one
important difference. It doesn't lose its
| | 03:37 | value when the function is done.
| | 03:39 | So look back at test1, typically
calling test1 will always yield the same
| | 03:44 | value, 2, if we increment it,
it's always going to revert back.
| | 03:48 | To show you what I mean, I'm going to
copy this whole thing again, and this
| | 03:53 | time I'll make it test3. There we go.
Then I'll take out the global line for
| | 03:58 | now. Once this whole thing is done,
then let's do, var++. So that's just going
| | 04:04 | to increment var. That's a
shorthand to say var=var+1. So it's going to
| | 04:11 | increment it one time.
| | 04:12 | Now let's try running this one and see
what happens. So I'm going to run it and
| | 04:17 | its 2 and 1, just like it was before.
Let's try running it a second time and a
| | 04:23 | third time here. So I'm going to call
it three times. Every time it's equal to
| | 04:29 | 2. This incrementation that we did,
it increments. So var is set to 2, it
| | 04:36 | outputs 2, and then var is set to 3.
The next time we call it, var = 2, var
| | 04:41 | outputs, var gets incremented, it gets set to 3.
| | 04:44 | But if we declare static in front of it,
static var with a default value of 2,
| | 04:52 | then when we call it every
time, it increments, 2, 3, 4.
| | 04:58 | So notice it's still a local value. It
didn't affect one. That's on our global
| | 05:05 | scope, it's still in the local scope,
but it's a static value now that keeps
| | 05:10 | its value and sticks around every time
the function is called. So it works like
| | 05:14 | a counter variable inside this function.
| | 05:17 | Now, while we won't use static
variables very often, it's a good tool to know
| | 05:20 | about, but even more importantly, I
want you to understand it so that you won't
| | 05:23 | be confused when we talk about a
slightly different application of the word
| | 05:27 | static when we get to object
oriented programming a little later.
| | 05:31 | There is going to be another use of
the word static and this is going to be
| | 05:33 | helpful to have this as a foundation
so that we can talk about that. A lot of
| | 05:37 | beginning programmers get the two
confused and aren't sure what the difference
| | 05:40 | between them is, but that won't happen for us.
| | Collapse this transcript |
| Making a reference assignment| 00:00 | In this movie we're going to talk
about references, specifically reference
| | 00:03 | assignment. References are going to
allow variables to refer to the same
| | 00:08 | content as other variables.
| | 00:10 | Open up basic.html and just do a
Save As on that and let's save this as
| | 00:16 | references.php, Reference Assignment.
So if we have, for example, a variable a
| | 00:30 | which is equal to 1 and then we have a
variable b which we set equal to a. Now
| | 00:35 | if we set b equal to something else,
like 2, then if we echo back those values
| | 00:43 | for a and b, we can guess what they are
going to be. It should return, returns
| | 00:48 | 1/2. Let's try it out and see.
| | 00:51 | I open up Firefox and let's bring up
references. There it is, 1 and 2, just
| | 00:59 | like we would expect. But what if
instead of doing that, we instead used a
| | 01:04 | reference and the way we use references
is to put an ampersand after the equal
| | 01:09 | sign. And that does what is
called Reference Assignment.
| | 01:13 | So now instead of b being simply equal
to the value of a, b references the same
| | 01:21 | thing as a. So the bit of computer
memory that's holding a's value, b is now
| | 01:26 | pointing at that same thing. The
easiest way to think about it is it's like
| | 01:30 | when you make an alias in the finder
in a Mac or when you use a shortcut on a
| | 01:34 | PC and you have a folder and you can
make a reference on alias or shortcut that
| | 01:40 | allows you to get to that same folder.
That's what we're doing here.
| | 01:43 | We're making it alias to it.
| | 01:45 | So now what happens when we set these
values. So let's save it. I'll erase
| | 01:50 | those because we don't know what it
returns yet and we'll hit Reload and we see
| | 01:54 | that it returns 2 and 2. Now the
reason why is because b points to a, so when
| | 01:58 | you change the value of b, it changes a
at the same time because they point at
| | 02:03 | the same thing. They are equivalent, b
and a. So make sure that you understand
| | 02:08 | that that's what a reference is.
| | 02:10 | Now why use references, why not just
use a or make a copy of a? One of the main
| | 02:15 | reasons is that we can delete our
reference b and a will still be there, just
| | 02:19 | like if we deleted a shortcut from my
Desktop, it does mean that the folder
| | 02:23 | that was there is completely gone,
we have just erased that shortcut.
| | 02:27 | So a lot of times we want to be able to
have that kind of disposable link there
| | 02:30 | that we can break and destroy but
still leave the underlying values intact.
| | 02:36 | When we decide that we're ready to
unset it, then we can just simply use
| | 02:39 | unset($b) and that will unset b for us.
Then let's just echo those values back
| | 02:46 | just to see what they are equal to
again and you will see that now a is still
| | 02:49 | equal to 2 but b is equal to nothing.
| | 02:52 | So that's the basic concept behind
references. We're going to look in the next
| | 02:57 | few movies at other ways
that we can make use of them.
| | Collapse this transcript |
| Using references as function arguments| 00:00 | In the last movie we learned about
references and how we can have one variable
| | 00:04 | that references the same value that
another variable references. It works like
| | 00:08 | an alias. Well, now I want us to
look at how we can pass in references to
| | 00:12 | functions. So the argument itself
that's being passed in is a reference.
| | 00:17 | Let me show you what I mean.
| | 00:18 | Here I'm in my references file that I
was just working on. I'm just going to do
| | 00:23 | a quick Save As on that and we'll just
call this one references_args and that
| | 00:29 | will help us keep them separate. Then
we'll make the name of it, References as
| | 00:34 | Function Arguments and we'll take
everything we're working on and just take it
| | 00:39 | out of there and let's try a real
simple function here. Let's so just say
| | 00:43 | function, we'll call it ref_test and
we'll pass in a variable. In there,
| | 00:49 | we're just going to do a real simple
transformation to that variable just so that
| | 00:53 | we can see whether the value gets affected.
You can just do +1 or something like
| | 00:56 | that. I'm going to do x 2.
| | 00:59 | Now we know that if I have a value
like a and then I pass in ref_test a and
| | 01:07 | then echo back the value of a. Stop
and look at that for a second and tell me
| | 01:11 | what do you think the value of a will be.
Remember what we know about local and
| | 01:15 | global variables. Hopefully, you are
able to tell that a starts out as 10, the
| | 01:20 | value of a gets passed into this
function ref_test as an argument. It gets
| | 01:25 | multiplied by 2, but then nothing ever
happens because this is a local scope,
| | 01:29 | it's the local value and a is a global value.
| | 01:33 | So when we come back and we echo a,
a has been unchanged. So let's just
| | 01:36 | demonstrate that just to make sure
that we're clear on that. It's the basic
| | 01:40 | things we're talking about
before with local ad global values.
| | 01:43 | So I'll open up Firefox and instead
of references, I'll just ask it for
| | 01:47 | references_args. There we are, value is
still 10, not 20 but 10. So it did not
| | 01:53 | change because this is the local scope.
| | 01:55 | We saw in the last movie how we
used ampersand with the equal sign for
| | 01:59 | Reference Assignment. We're going to
use that ampersand again here, but this
| | 02:03 | time we're going to put it in front of
the argument. So it will be like that.
| | 02:05 | It will be ref_test(&$var).
| | 02:10 | So what we're saying here now is when
something comes in, don't take its value,
| | 02:16 | make a reference to that value. So
therefore, a and var are going to point to
| | 02:22 | the same thing. Now let's watch what
effect that has. I'll save this. We'll go
| | 02:27 | back and we'll reload the page and now
notice it's equal to 20. Because var is
| | 02:34 | pointing at that same thing
as a, it's like an alias now.
| | 02:38 | So in the same way that a shortcut or
an alias on your computer that's, let's
| | 02:41 | say, an alias for a folder, if you
drop a file into that folder, it both goes
| | 02:46 | into the alias and into the actual
folder that exists in both places because
| | 02:50 | they point to the same thing.
| | 02:52 | So that's what's happening here, it's
affecting that same value because they
| | 02:55 | are both pointing at the same thing.
Now if you stop and think about it for a
| | 02:58 | second, this is exactly the same as if
we had taken the & out and just simply
| | 03:04 | called global $a and then simple made
this a as well, right. Let me change this
| | 03:12 | one too. Those have the same effect.
Let's just try it, all right, exact same
| | 03:18 | effect. In fact, we can actually not
even pass in a value here if we're working
| | 03:22 | with global, all right.
| | 03:24 | So there is a little bit of
difference in that, we don't have to pass in a
| | 03:27 | value when we use global, when we're
using the args version, we do, and we have
| | 03:33 | the ability to name it something else.
We don't have to have the same variable
| | 03:37 | name as we had when we use global. So
we're able to rename it in the local
| | 03:41 | context but have it still
reference the same thing.
| | 03:44 | So it's going to be a little bit up to
you to decide whether you want to bring
| | 03:47 | in a global value or whether you want
to simply work with it as a reference.
| | 03:51 | They are going to achieve a lot of
the same things. It's just going to be
| | 03:54 | syntactically a little bit different.
So make sure you understand both of them
| | 03:59 | and then you will be able to use
whichever one feels right in each situation.
| | 04:02 | In 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:00 | In this movie, we're going to continue
to talk about references. We have seen
| | 00:03 | what references are and we have seen
how to pass them in as arguments to a
| | 00:06 | function. In this movie I want a take a
look at how we can return references as
| | 00:11 | return values out of a function.
| | 00:13 | To start with, I'm going to create
a new file. I'm just going to use my
| | 00:15 | references_args file and I'll just do
a Save As on that and we'll call this
| | 00:21 | References as Function Return Values.
Now I'll go ahead and get rid of all of
| | 00:33 | the functions I had there and I'll
write in a new function and it's going to be
| | 00:38 | function ref_return and I'm not
going to pass in any arguments to it, but
| | 00:44 | instead I'm going to have a global
value that I'll pull in, global a.
| | 00:48 | I will use a and just do a simple
transformation on it so we can see that it
| | 00:53 | has changed, and last of all return
that value. Then I'll go ahead and set a
| | 01:00 | equal to 10 and if I have b equal to
ref_return, right, then that should take
| | 01:09 | whatever return value came back from
the reference return, and it should put it
| | 01:14 | into b. So in order to test this out,
let's echo those out so we can see them
| | 01:20 | and I'm just going to do a real simple
echo on those and let's see what they
| | 01:24 | are equal to.
| | 01:25 | So I'll save that, come back to the web
browser and we'll just do returns.php.
| | 01:31 | So they are both equal to 20. It starts
out a is equal to 10, then we run this
| | 01:37 | function which brings in a as a global,
changes its value. It's a global so
| | 01:42 | we're affecting that global value of a
and then it returns it to b so b is also
| | 01:46 | equal to 20, fair enough.
| | 01:48 | But now notice what happens if we say
well, b is equal to 30, and let's take
| | 01:53 | that same line and let's test that
out. Now, b equals 30 and a equals 20,
| | 02:00 | right? we're not using any kinds of
references. So b is just a separate
| | 02:04 | variable and when we change its value,
it doesn't affect a, right? Because
| | 02:07 | we're not using the references.
| | 02:08 | Now we talked about Reference
Assignment before and we learned how to simply
| | 02:11 | use the & after an = for a reference
value and that we used it before we would
| | 02:18 | say that, b references a. Let's save
this and let's just try it here and see
| | 02:23 | what happens.
| | 02:25 | Nothing, nothing changed, it gave us
the same value back, right? Because it's
| | 02:30 | returning a value to us. Now it says
return a here, but it's not returning the
| | 02:35 | actual variable a. It's not returning
a reference to a, it's returning the
| | 02:40 | value, the same way as when we passed
in arguments and we said that we were
| | 02:44 | going to have the first argument be
passed in be a. Without that Reference
| | 02:49 | Assignment, we were passing
in the value of a which was 10.
| | 02:53 | So in this case, what we're returning
is the value here, not a, just be clear
| | 02:58 | on that, it's returning the value. The
number 20 is being returned and that is
| | 03:03 | being set up as a reference, b is
referencing 20, which really is kind of
| | 03:07 | meaningless for it to reference 20, right?
It's equal to 20; it's the same thing.
| | 03:10 | So in order for this to return a
reference, we need to put another & here at
| | 03:16 | the beginning of the function name.
So that's where it's going to go, it's
| | 03:20 | going to let us know that we're
returning, it doesn't go down here, it goes up
| | 03:23 | at the beginning of the function name
and it says return a reference value.
| | 03:26 | Whatever return value comes
out of here, will be a reference.
| | 03:30 | That means that what's being returned
out of here as a reference, so that's
| | 03:33 | returning actually a is being returned,
but if we don't have this one then b is
| | 03:38 | still just being set to the value of a,
right? So we need both of them. It's
| | 03:42 | important to have both so that the
reference is being sent out of the function
| | 03:47 | as a reference and it's being set to b
as a reference. You have to have that
| | 03:52 | handshake between the two.
Otherwise it won't work.
| | 03:55 | So now let's try it and let's reload it
and we see that now in the second line,
| | 04:00 | a and b are both equal to 30 because
when I set b equal to 30 here, it also
| | 04:05 | changes a at the same time, because
they are a reference and we know how
| | 04:08 | references work, we have seen that.
| | 04:09 | So once again, if you need to play
with it a little bit, try taking out the &
| | 04:13 | here and see what you get and try
taking out the & here and see what you get.
| | 04:17 | You will see that it doesn't work in
either case. It's because we're passing
| | 04:20 | out a reference and then we're setting
b to that reference. It's two steps to
| | 04:25 | that process. So make
sure you are clear on that.
| | 04:28 | Before you move on, I just want to give
you another example. I'm just going to
| | 04:31 | skip down here and I'll put another
function which I have called increment and
| | 04:35 | this one instead using a global
variable is going to use static variable, which
| | 04:38 | is going to start out by initializing
to 0 and then we'll increment it by 1 and
| | 04:43 | return that value. It makes sense,
its called increment. But it's going to
| | 04:46 | return a reference to that static variable.
| | 04:49 | So if we catch that value of increment
in a, then the variable will increment.
| | 04:54 | a will now be a reference to that
increment. So therefore, if we call it a
| | 04:59 | second time, just on its own, like that,
what will be the value of a be? a is
| | 05:04 | still pointing to the static variable.
When we call the function again, even
| | 05:09 | though it's not doing any assignment,
it increments that static variable. So a
| | 05:12 | still points to it. Even more
interesting is that we can increment it this way,
| | 05:17 | because a points to the same
thing as increment. So it's once again
| | 05:22 | incrementing that static
variable. So either one works.
| | 05:26 | We will do the same thing one more time,
increment, and then last of all, just
| | 05:31 | so we can prove to ourselves that this
has been working, let's do an increment.
| | 05:35 | So last of all, just so we can prove
to ourselves that this has been working,
| | 05:37 | let's echo up the value
just so we can see what it is.
| | 05:40 | So I'll save this and let's go back and
let's reload it and you will see that a
| | 05:44 | is equal to 4. The first time it
increments it, then it increments it again,
| | 05:48 | then again, and then again, four times.
The static variable in there is just
| | 05:53 | getting incremented and we can do
it either way, because we have made a
| | 05:56 | reference to a value inside this function.
| | 05:59 | These reference techniques that we
have been learning will become more useful
| | 06:02 | later when we start working with
object oriented programming and with
| | 06:05 | databases. We'll talk more about
references after we talk about objects.
| | 06:09 | Let'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:00 | I would like to start out this chapter
on object oriented programming or OOP by
| | 00:05 | first talking about the concept and the
basics of object oriented programming.
| | 00:09 | PHP is the scripting language or may
also be also called a procedural language.
| | 00:14 | It's not really a true object
oriented language. Instead, it's a scripting
| | 00:17 | language that has some object oriented
features built into it. PHP 4.0 first
| | 00:22 | gave a few limited object oriented
features. It really wasn't until version 5.0
| | 00:27 | that we had full object oriented support in PHP.
| | 00:30 | Do you need object oriented programming?
If scripting and procedures are all
| | 00:34 | you want PHP to do, then you probably
don't need OOP. In fact, it might even be
| | 00:38 | a bad choice. After all, if it ain't
broke, don't fix it! But if you are
| | 00:41 | pushing PHP harder than that and
asking it to do a lot of complex work, then
| | 00:45 | OOP may be exactly what you need.
| | 00:48 | Don't let any preconceived notions
about what a scripting language can or
| | 00:51 | should do, limit you from the possibilities
of object oriented programming in PHP,
| | 00:55 | and most of all, don't be afraid
of it. Here is my rule of thumb.
| | 00:59 | I always say that for a simple site, object
oriented programming adds unnecessary complexity,
| | 01:03 | but for a complex site, object oriented
programming adds necessary simplicity.
| | 01:08 | Now the next question you may be asking
yourself is what are objects? Well,
| | 01:14 | in the simplest way, objects are simply
grouping code together by a common theme.
| | 01:19 | So if you think back to some of the
work that we did in the Essential Training,
| | 01:22 | we had a lot of different functions
related to working with forms. We could
| | 01:26 | have rolled all of those up into a
form object and then our code would stay
| | 01:31 | grouped together and we would have
been able to find all of those form
| | 01:34 | functions in our form object.
| | 01:37 | Now there is a more complex way that we
can use them as well, which is not just
| | 01:40 | to group them together, but actually
to abstract the structures in our code
| | 01:44 | into objects. In other words, to make
our software objects seem very similar to
| | 01:49 | real world objects. And this makes
sense because a lot of what we're doing on
| | 01:53 | the web, we think of as objects.
We have a page, a page could be an object
| | 01:58 | or a form, a form could be an object.
| | 02:00 | Those could be physical objects in the
real world in the same way or we could
| | 02:04 | have customers, students, shopping carts.
Those are all objects and we can hold
| | 02:10 | them in our head and think about
them as objects. Objects have not only
| | 02:14 | functions that allow them to do
things, but they have attributes as well.
| | 02:19 | So we would have a student who has a
first name and a last name or a shopping
| | 02:23 | cart that has a total quantity in it.
Those are attributes of each of those
| | 02:27 | objects, and it's easy for us to think
about because we're used to thinking of
| | 02:30 | objects in our head in that sort of way.
| | 02:32 | It will become clearer what objects are
as we start working with them, but let's
| | 02:36 | first take a look at some typical PHP
code that we might have in a project
| | 02:40 | we're working on. We might have a
student whose first name is John, his last
| | 02:44 | name is Doe, we might have another
student Mary and Smith. Then if we wanted to
| | 02:48 | find out a student's full name, we
would have a function where we could pass in
| | 02:51 | those two values, Mary and Smith, and
it would return Mary Smith to us with the
| | 02:56 | space in between them. We have been
doing that kind of thing before, but we can
| | 02:59 | already see how this is going to start
to break down if we start having a lot
| | 03:02 | more complexity.
| | 03:03 | This is just where we're dealing with
two students and a simple function to put
| | 03:07 | their name together. What if we
had a lot of functionality then?
| | 03:10 | What if we wanted to know the courses that
the student is in? I can have a simple array
| | 03:15 | that defines what each of those is,
but what if each of those has some
| | 03:18 | complexity to it? What if I don't want
to just have student one's course be English
| | 03:22 | but the English class that starts at 1
o'clock on a Wednesday. Then we start
| | 03:26 | having a lot more complexity there
and objects are going to serve us well
| | 03:30 | because they are going to allow us to
pull all that complexity into a very
| | 03:34 | simple data structure that we can work with.
| | 03:37 | So why are objects going to be useful
for us in programming? They are going to
| | 03:40 | give us better code organization and
maintainability. If we group all of our
| | 03:44 | functions and variables related to
forms into something that's a form object,
| | 03:49 | then we'll know right where to go when
we need to make a change to the forms.
| | 03:53 | If we roll all of the codes related to
a student together into a single student
| | 03:58 | object, then when we want to make a
change to the way that that code works,
| | 04:02 | we know right where to go. We go straight
to that object and we make the change.
| | 04:05 | It also adds clarity and reduces
complexity and that's because we're able to
| | 04:10 | think about these complex bits of
data, all of the functions related to
| | 04:14 | students, all of those attributes,
however much complexity we give to it,
| | 04:17 | we can think of as a student and student
has all of that functionality built into it.
| | 04:24 | So it becomes very clear, we have a
student and a student object. It can be
| | 04:27 | asked questions, it can be asked to do
things, it can be asked to return data
| | 04:30 | to us, but without us having to
navigate all that complexity each time.
| | 04:34 | The simple rules that we put into
objects can actually allow for complex
| | 04:38 | interactions. Let's imagine for a moment
that we have a classroom and we have a student.
| | 04:43 | We can issue a simple statement like
put the student in the classroom and
| | 04:46 | the objects themselves can have complexity
built into them that says, well, before
| | 04:51 | you do that, check and make sure that
the class is not full, make sure that the
| | 04:54 | student doesn't have a class that
conflicts with the time of this class,
| | 04:57 | for example. Then once it puts the student
in there, it can update the total class count
| | 05:01 | and the class can keep
track of how many students are in it.
| | 05:04 | So all that complexity can be built in
and all we have to do is say, put the
| | 05:08 | student in the class and those simple
rules will all kick in. And because of that
| | 05:11 | it's going to emphasis the data over
the procedure. The procedure is going
| | 05:15 | to be already preprogrammed for us
inside these objects and we can really work
| | 05:19 | on just the data and how the data interacts.
| | 05:22 | Objects are also going to give us code
modularity. Because the code is going to
| | 05:25 | be broken into discrete sections, we
can go in and work on one section at a
| | 05:30 | time and not worry about hurting
something else. This is great if we have a
| | 05:33 | team of developers, because different
developers are going to be working on
| | 05:35 | different sets of objects and not
interfere with each other; the code will be
| | 05:39 | separated. And last of all is code
reusability. If we write a complex shopping
| | 05:44 | cart object, then all of that
functionality is there when we take that same
| | 05:48 | shopping cart object and
use it for another client.
| | 05:51 | And last of all, objects are well
suited for databases. If we have a table of
| | 05:56 | students, then each of those students
can be an object. If we have a table of
| | 06:00 | classrooms, then each of those
classrooms can be an object. If we have a table
| | 06:04 | of cars, each car can be an object and
so on. So object oriented programming is
| | 06:09 | going to a nice fit for working with databases.
| | 06:11 | Now I think that's enough background
on the concepts and advantages of using
| | 06:15 | objects. I think it will start to
make a little more sense as we start to
| | 06:18 | actually code and that's what we're
going to do in the next movie where
| | 06:20 | we start defining classes.
| | Collapse this transcript |
| Defining classes| 00:00 | Now that we have gone over the
fundamentals of objects, it's time to see how
| | 00:04 | we can actually define an object, and we
do that by defining an Object class. So
| | 00:09 | what we're going to be working here
are classes, and we're going to be seeing
| | 00:11 | in this movie how to define a class.
| | 00:13 | To start with, I'm just going to open
up TextMate to a new file and I'll just
| | 00:18 | do a Save on that file into my
sandbox and I'm just going to call it
| | 00:22 | class_example.php. I'm not going to
have any HTML in it; I'm just going to
| | 00:28 | start out with some PHP.
| | 00:29 | Now every class definition begins with
the keyword Class and then right after
| | 00:34 | that is the class name. So it could be
for example, Student. Now, it's worth
| | 00:39 | noting that it's in CamelCase, which
means uppercase for the first letter, and
| | 00:44 | then in the other words would also be
capitalized. So for example, Portfolios
| | 00:49 | let's say it would be a
StudentPortfolio and you see the CamelCase there.
| | 00:53 | That's because of the hump that's
created by the capital P that's there.
| | 00:57 | So I'm going to create my first class.
I'm just going to call it Person, and
| | 01:00 | then we're going to have a pair of
curly braces, and everything that's inside
| | 01:03 | those curly braces is going to be the
definition of the class. Principally,
| | 01:07 | that's going to be its
variables and its methods.
| | 01:09 | Now sometimes you will see this
written like this. That's fine. It has the
| | 01:13 | exact same effect. White space
doesn't really make a difference in PHP.
| | 01:17 | I'm going to tend to write them like that.
So whichever way you prefer to have your
| | 01:20 | curly braces. That's all
there is to defining a class.
| | 01:23 | Now it's not a very exiting class,
there is nothing in it, but that is now a
| | 01:27 | class. Whenever we create a class, PHP
keeps track of the fact that it has been
| | 01:31 | created. It's similar to how required
ones keeps track of all the files that
| | 01:35 | have already been required. Remember there
is an array that we can look at to see that.
| | 01:39 | We can have classes = get_declared_
classes and that's a special function that
| | 01:47 | will grab all the classes that have
been declared and put them in our variable
| | 01:51 | and then we can do foreach ($classes
as $class). We'll just do a simple for
| | 01:58 | each loop through them to see them,
echo $class and then we'll just put a
| | 02:04 | little br tag at the end. There we go.
| | 02:07 | So now if we just try running this
simple script, it will define the class.
| | 02:11 | There is nothing in it but it will
still define it in anyway. We'll then add it
| | 02:14 | to the declared classes, and we can pull that value
back and output each of our classes. Let's just try that.
| | 02:19 | So I'll go into Firefox, and we're
going to be in our sandbox again, but this
| | 02:24 | time class_example.php. There is a
list of all the declared classes.
| | 02:30 | Now you see there is a whole lot of them.
A lot of these are already declared by PHP
| | 02:34 | for us, but if we do a search here,
actually down at the very bottom is Person.
| | 02:38 | That's the one that we did. So PHP
defines all these other classes for us, and
| | 02:42 | then Person is the one that we defined.
| | 02:45 | Now there is another way that we can
do this besides listing them all out,
| | 02:48 | let's take all of this code real quick,
and we'll just comment it out.
| | 02:55 | Instead, let's ask if class exists and
then in quotes we'll put Person. Then if
| | 03:05 | it exists then echo That class has
been defined and we'll put a br tag after
| | 03:14 | it, and if not, we'll say else echo
Class not defined! we'll put our br tag again.
| | 03:24 | So that's just going to do a quick
check to see has the class been defined or
| | 03:31 | not, does the class exist? So we'll
save that and let's just try reloading that
| | 03:35 | page. We'll see how that works. There
we go. So that class has been defined.
| | 03:44 | If we change it to something like
Animal and then we go back to Firefox,
| | 03:48 | and we reload the page,
we'll see Class not defined.
| | 03:51 | So that's one good way to find out if
a class exists or not. So even though,
| | 03:55 | we have done a very unexciting class at
this point, we already see that it's been
| | 03:59 | created and we can find out a little
bit of basic information about it. In the
| | 04:02 | next movie, let's take a look at how
we can add some functionality to our class.
| | Collapse this transcript |
| Defining class methods| 00:00 | In the last movie, we saw how easy it
is to create an object class, but our
| | 00:04 | class wasn't very exiting. What we need
to do is add some more functionality to it
| | 00:08 | and that's what we're
going to do in this movie.
| | 00:09 | Now, classes can contain methods.
These are the same things as functions but
| | 00:13 | generally they are called functions
when they are on their own and methods when
| | 00:17 | they are inside of a class. Now I may
slip up from time to time and call it a
| | 00:20 | function but keep that clear.
If it's on its own, it's a function;
| | 00:23 | if it's inside a class, it's a method.
That's the standard convention of
| | 00:27 | object oriented programming.
| | 00:28 | Now, I want you to go ahead and do a
Save As on this file that we're working with,
| | 00:30 | because I want you to still have
this code down here for your reference,
| | 00:35 | but I wanted to get it out of our way
as we continue working. So let's do a
| | 00:38 | Save As and we'll just call this class_example2.
| | 00:44 | Then we'll go ahead and get rid of
all of this. We'll leave our class
| | 00:47 | definition because we're going to
continue to work with that and improve it.
| | 00:50 | So I'll save this file and now we're
going to add our first method to it. Now,
| | 00:54 | even though object-oriented
programming says we should call it a method,
| | 00:56 | we actually use the keyword function still
to define it, just like we normally do.
| | 01:01 | So let's make one just called say_hello,
and this is just going to echo back,
| | 01:06 | Hello from inside a class. Everything
is still the same as we normally do with
| | 01:14 | the function. It's just been rolled up
inside of this class, so that it's now
| | 01:18 | one of the methods of the Person class.
So say_hello is a method of the Person class.
| | 01:23 | Now just like we did with seeing what
classes are defined, we can also find out
| | 01:27 | what methods are defined. So $methods =
get_class_methods ('Person') and then,
| | 01:37 | we 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:52 | Let's go ahead and save this and try
it out. I'll save it and let's open up
| | 01:55 | Firefox and reload, class_example2, say_
hello. There are the class methods that
| | 02:03 | belong to person say_hello, and we
also can do the same kind of thing that
| | 02:06 | we did before, or we can actually query if
(method_exists and it will return true
| | 02:13 | or false for whether or not the method
exists and then we can put in the object
| | 02:17 | name, Person, and then the
method name. So say_hello.
| | 02:23 | So we'll check to see whether it exists
or not, return true or false, and then
| | 02:26 | we can just give a simple echo Method
does exist. Let's go ahead and keep it
| | 02:34 | nice and friendly. We're putting a br
tag in there, else, and then we'll just
| | 02:40 | do echo "Method does not exist." Let's
save that and try it out. Put our br tag
| | 02:50 | at the end. So there it is, Method does exist.
| | 02:58 | Now if we try something else like say
_hello_to_me and then we go back to
| | 03:05 | Firefox, reload it, Method does not
exist. So we can check to see whether
| | 03:10 | methods exist the same way that we can
check to see whether classes exist, and
| | 03:13 | we can get a list of all those methods
if we want. But we still haven't seen
| | 03:16 | how to actually use this functionality.
| | 03:18 | We have been able to put in
functionality to our class, but we haven't been
| | 03:22 | able to use it yet. In order to do that,
we're going to need to talk about how
| | 03:25 | to instantiate a class and we're
going to do that in the next movie.
| | Collapse this transcript |
| Instantiating a class| 00:00 | In the last couple of movies, we
created a class and gave it some very simple
| | 00:03 | functionality, but we haven't seen
how to actually use our class or its
| | 00:07 | functionality. In order to do that,
we're going to need to talk about how to
| | 00:10 | instantiate a class. Now that may be a
word that's not very familiar to you,
| | 00:14 | if you haven't worked with object
oriented programming before.
| | 00:16 | What we're going to be doing is
creating an instance of the class and that's
| | 00:20 | why we say instantiating. It's a
fancy way of saying we're creating an
| | 00:24 | instance of the class. Think of a
class as a pad of stationary or let's say
| | 00:31 | maybe one of those While You Were
Out pads where you take messages for
| | 00:34 | someone who has gone, and it has a
space for the first name and the last name
| | 00:37 | and the person who called, and their
phone number, the time they called, all of that.
| | 00:41 | So think about a little pad like
that that's sort of preprinted with all
| | 00:44 | this information.
| | 00:45 | That's going to be our class is that
pad of paper. What we're going to do with
| | 00:49 | each instance is tear off one of those
sheets and fill it out. Each instance is
| | 00:53 | like another page. So every instance is
different from each other because they
| | 00:57 | have been filled out with different
information, but they fundamentally are the
| | 01:00 | same. They are all a 'While You Were
Out' note, and that's different from let's
| | 01:04 | say a doctor's prescription pad. That's
a different class and it has different
| | 01:08 | fill in the blanks on it, for filling
out a prescription, and each of those
| | 01:12 | will be very similar to each other,
they will all be of the same class, but
| | 01:15 | they will be different from
our 'While You Were Out' notes.
| | 01:17 | So what we're going to be working on
now is how to sort of tear off one of
| | 01:20 | those pages of stationary and fill it
out with some more specific information.
| | 01:24 | Let's see how to do that. I'm going
to take my class_example file. I'm just
| | 01:27 | going to do another Save As on it,
just that we still have a record of that
| | 01:31 | work that we were just doing. I'm
going to hit class_example3, and I'm just
| | 01:35 | going to get rid of all of this at the
bottom, but I'm going to leave the class
| | 01:39 | that we still have been working with at
the top as we continue to expand that.
| | 01:42 | Now, in order to instantiate a class,
what we do is we say New and then Person
| | 01:48 | with parenthesis. That creates a new
person. Now, it creates it and then it
| | 01:53 | does nothing with it. It just creates
it and it's not accessible to us anymore.
| | 01:57 | So we need to assign it to a variable
so that we can work with it. So $person =
| | 02:02 | new Person object. So take the class
Person, tear me off one of those sheets,
| | 02:07 | and I'm going to fill it out.
| | 02:08 | Now we don't have a place for first
name or last name or anything like that
| | 02:11 | yet, we'll get to that later. But what
we have done is simply pulled off one of
| | 02:15 | those sheets from our memo-pad and
assigned it to Person. Now we can have
| | 02:19 | another one, it could be
$person2 = new Person.
| | 02:25 | Now, these are two different
instances of the same class, Person. Make sure
| | 02:31 | that you understand that, this is two
different occurrences of the person. So
| | 02:35 | I'm a person, you are a person, Steve
is a person, Bob is a person, right?
| | 02:39 | All of us have some things in common. We
all have a first name and a last name,
| | 02:43 | we all have two arms and two legs, and so
on. So we're all of the same class, but
| | 02:47 | each one of us is a different instance,
a different occurrence, and that's what
| | 02:51 | we have got going on here.
| | 02:53 | Now we can find out what class an
instance belongs to. For example, we can say
| | 02:56 | echo get_class and then ($person) and
let's go ahead, and like we always do,
| | 03:03 | just put a nice br tag at the end of
that and that will return what class this
| | 03:08 | instance of person is.
| | 03:10 | Obviously, we have named it Person, so
it's very obvious. But if we called it
| | 03:13 | Bob, or if we called it Student, then
it might not be clear that it's a person
| | 03:18 | that we're talking about. It's a
helpful way to make sure that we know what
| | 03:21 | class we're talking about, and there
is another way that we can do it as a
| | 03:24 | Boolean, just like we
have been doing the others.
| | 03:25 | We can say if (is_a, and then we can
put in, ($person, and 'Person')). So if
| | 03:33 | person is a person, it kind of reads
weird and backwards, but what we're saying
| | 03:38 | is if this instance, this person
variable is of the class Person, then return
| | 03:45 | true or false, and we can say echo "Yup,
it's a Person", or else, echo "Not a
| | 04:00 | person". So that's a way we can test.
We can find out what class it is or
| | 04:07 | we can test whether it is or not.
| | 04:09 | Let's just try those two out real quick.
We'll go into Firefox and we'll bring
| | 04:12 | up class_example3. So it comes back and
tells us it's of the class Person, and
| | 04:18 | then it says Yup, it's a person. Now,
if we were to make it a different class
| | 04:22 | and say is that of the class animal,
even though animal is not defined? Come
| | 04:26 | back here and no, it says not a person,
but obviously it's returning a Boolean false.
| | 04:31 | So now you know how to create an
instance, and once we have an instance, then
| | 04:36 | we can activate the functionality
that's inside of that object. So the way
| | 04:41 | we do that, the way we can call our
functions in there. It's a method. The method
| | 04:46 | say_hello is we simply say Person, and
then an arrow. I'm going to always call
| | 04:53 | that an arrow, but it's the minus sign
and the greater than and then say_hello
| | 04:58 | with the parentheses after it, just
like we do it with our functions. It's
| | 05:02 | still a function. We still need to
have these parentheses to indicate it.
| | 05:05 | All we're doing is saying look
inside the person and in there, find the
| | 05:10 | function called say_hello, so that
arrow notation, we're going to get very
| | 05:13 | familiar with. You will see that I
don't need to do any kind of echo before it
| | 05:17 | because the echo is already in my
function. So let's just try that out real
| | 05:20 | quick. Go back to Firefox, and we'll
just reload the page, Hello from inside a class.
| | 05:26 | So now we have created a class,
we've put a function in it, we've made an
| | 05:30 | instance of the class, and we've
called the functionality that's inside of it
| | 05:35 | by using that arrow notation. So at
its most fundamental, that's all there is
| | 05:39 | to actually using classes.
| | 05:41 | With just this much knowledge, you
already could wrap up a lot of your
| | 05:45 | functions, put them into classes and
make them class methods, and call them
| | 05:49 | using the notation that we have here.
Now earlier, we talked about references
| | 05:53 | and how references would play an
important part of working with objects, and in
| | 05:57 | the next movie, we're going
to see how that's the case.
| | Collapse this transcript |
| Referencing an instance| 00:00 | We talked about reference assignment
back in Chapter 2 but now I want to talk
| | 00:03 | about how references apply to objects.
Now the good news is that you actually
| | 00:08 | don't have to do anything. You just
need to understand what's going on.
| | 00:12 | Reference assignment is automatic for
objects in PHP 5. Now that wasn't true
| | 00:16 | back in PHP 4. Let's first take a look
at why it's true, and why we would want
| | 00:21 | this function to be automatic.
| | 00:22 | Let's imagine that we have a new person.
So we have created a new person,
| | 00:26 | we have assigned it to a variable. Then
let's say somewhere else in our code later on,
| | 00:29 | we decide to say well, the
customer is equal to that person.
| | 00:32 | Now if we don't use reference assignment,
then that would mean we would need to make a copy
| | 00:37 | of the value just like we did back
when we had A and B, and then we said B = A.
| | 00:42 | If we don't use the reference
assignment, they don't point to the same thing,
| | 00:45 | it actually duplicates the value, but
in this case, the value is an object, and
| | 00:50 | an object contains a lot of code. Now
so far, a person object has been very
| | 00:55 | simple. We just have that say_hello
method, but even that would get copied, and
| | 00:59 | if we had 20, 30, 40 different
methods inside the Person class, then all of
| | 01:05 | those would get ported when we made
the copy. So each and everyone would have
| | 01:09 | that same functionality.
| | 01:10 | If you go back to the metaphor that
we're using for tearing off a sheet of a
| | 01:14 | stationary or a notepad, then we
would basically be making another page,
| | 01:19 | another sheet of paper, and copying
all the information down on it too, and
| | 01:23 | then we would have two pieces of
paper that are identical. What we actually
| | 01:26 | want is a reference to the same one.
So because objects can be very large and
| | 01:31 | take up a lot of memory, it's going to
be more efficient for PHP to not make
| | 01:34 | copy of the whole object, but to
make a reference assignment instead.
| | 01:38 | Now, it's no problem if you still
include that reference assignment, and you go
| | 01:42 | ahead and put that em percent there. In
fact, it's common practice and we'll be
| | 01:46 | doing it a lot throughout this tutorial,
so don't be surprised if you see it
| | 01:49 | there. If nothing else, it
demonstrates what the programmer's intent is, even
| | 01:54 | if the PHP engine would have
already done the same thing for you.
| | 01:57 | In case you are wondering, we'll
take a little later about how you would
| | 01:59 | actually copy objects if you wanted
to copy them. But there is another
| | 02:03 | important way that we reference the
instances of a class. Now notice that I
| | 02:06 | said instances, it only applies
to instances and that's with the
| | 02:10 | Pseudo-variable: this. Let's take a look at it.
| | 02:14 | So here I'm in the class_example we're
just working on. I'm just going to do a
| | 02:17 | Save As and we'll make this class_
example4_PHP and just like before, I'm going
| | 02:23 | to get rid of everything that was down
here and we're going to continue to work
| | 02:27 | on our class. The pseudo-variable:
this with a dollar sign in front of it can
| | 02:31 | be used as a reference to refer to the
calling object when you want to call a
| | 02:35 | method from within an object.
| | 02:37 | Let me show you what I mean. So right
now, we have echo "Hello from inside a
| | 02:42 | class." Well, what if we wanted to
actually have the class name? So instead of,
| | 02:45 | Hello from inside a class, let's
change it to say From inside the class, and
| | 02:50 | then we'll have it put in the class
name here. So I'll put in two periods to
| | 02:55 | append this together, and then we'll
use our get_class method that we saw
| | 02:59 | earlier. How do we talk about the class
of this instance, and the way we do it
| | 03:04 | is with this. There is a dollar sign
in front of it, and then this. What we
| | 03:08 | mean is this instance.
| | 03:11 | Now right now, we're talking about
the class and the class is the same for
| | 03:14 | every instance. That's not important.
What's important here is that we're
| | 03:17 | asking it to use this as a
reference for the instance and get_class is
| | 03:22 | something we've applied to instances earlier.
| | 03:24 | So let's just try that out real quick.
We're going to go ahead and need to
| | 03:27 | create a new instance, person = new
Person and then we'll tell that person that
| | 03:34 | it should call the say_hello
method. So let's try that out.
| | 03:39 | We will go back to Firefox and this
time it will be example number 4, Hello
| | 03:47 | from inside the classPerson. Now, I
forgot my space in there, but you get the
| | 03:50 | idea. Here we go. So that's how we
reference an instance. So let's do another
| | 03:55 | one real quick. We'll just type
function and then hello, and then let's have it
| | 04:02 | call this and say_hello.
| | 04:05 | So now, we have got one method
that's calling another method.
| | 04:10 | So what do you think will happen if you come down
here and simply call our hello method in addition?
| | 04:15 | Let's go back and try it.
You can see it does the same thing.
| | 04:20 | So this, with the dollar sign in front of it,
is the way that we're going to refer
| | 04:23 | to the instance and call different
aspects of that instance from inside the
| | 04:28 | class, only inside the class
is where we're going to do that.
| | 04:31 | In the next movie, we'll take a look
at how we can start to define some class
| | 04:35 | properties, so that we can
continue to add complexity to our class.
| | Collapse this transcript |
| Defining class properties| 00:00 | Now, in addition to methods, classes
can also have their own variables that
| | 00:04 | belong only to the class, and these
are also called properties or sometimes
| | 00:08 | attributes. Attributes of the class.
Or instance variables. And we now know what
| | 00:13 | an instance is, so it make sense that
it's a variable inside an instance.
| | 00:16 | It's an instance variable.
| | 00:18 | So you hear me as all three of
those words interchangeably. I may say
| | 00:21 | properties, attributes or instance
variables. And in every case, what I mean
| | 00:24 | are the variables that belong inside a class.
| | 00:27 | Let's take a look at how we can define
these. So I'm inside the class_ example4
| | 00:31 | file I was working on and I'm just
going to go ahead and do a Save As on that,
| | 00:34 | just so that we can start the new file
and not worry about losing our old work.
| | 00:38 | So I'm going to declare
some variables here at the top.
| | 00:42 | Now, normally you would think we would
just declare variable like first_name.
| | 00:47 | That's the way we're used to just being
able to define a variable name. But the
| | 00:50 | one difference is that inside a
class we have to put var in front of it.
| | 00:55 | Now, in the global scope var is optional.
We can just have the dollar sign and
| | 00:59 | it will know that we mean var, but
inside the class, var is something that
| | 01:03 | we definitely need to let it know this is
a variable, and so just var first_name
| | 01:08 | and semicolon and it's not equal to
anything. It just being created. It just
| | 01:12 | exist, it's there and it's waiting for us.
| | 01:16 | So let's go ahead and create another
one, we'll just make it var last_name.
| | 01:21 | Now, we can assign values so for
example, let say we have var arm_count = 2.
| | 01:28 | That sets the default value to arm_
count. It's the same way that we have been
| | 01:32 | making assignments to variable in the
past. But we still need to var in front of it.
| | 01:36 | Let's do var leg_count = 2. So by
default every instance of the person_class
| | 01:44 | that we create will have two arms and
two legs. It will have a first name and
| | 01:47 | last name but they won't be equal to anything.
| | 01:50 | So let's try this out. Go ahead and
take away the say_hello message that we had,
| | 01:54 | and let instead try to access
these attributes. So echo person and then
| | 02:03 | their arm_count with nothing after it.
And that will reference the attribute arm_count.
| | 02:10 | Now notice that there is not a dollar
sign here. That would make it a dynamic
| | 02:14 | variable. like we talked about back in
Chapter 2 a variable, variable name. All
| | 02:19 | we need is the arrow notation
and then the name of the attribute.
| | 02:24 | Now. if it had parenthesis after it,
it would go looking for a function,
| | 02:28 | otherwise it goes looking for a
variable and that's how it knows the
| | 02:32 | difference. It doesn't need the dollar
sign anymore to know which one it is. It
| | 02:36 | uses the presence or absence
of those parenthesis to know.
| | 02:38 | So let's try this out. Let's go
back into Firefox and let's open up
| | 02:43 | class_example5 and there it is 2.
| | 02:45 | So return back to arm_count was 2. Now,
we can also set values this way, let's
| | 02:51 | say for example, person arm_count it's
going to be equal to 3, and while we're at it,
| | 02:58 | let's go ahead and say person first_
name it's going to be equal to Lucy. So
| | 03:05 | I don't think we need to actually
echo those back and try them out.
| | 03:08 | I think you understand what's going on there.
| | 03:10 | Now, this is where our OOP gets its
power, because now we can have different
| | 03:14 | instances that are different. So we
can have new_person = new Person and that
| | 03:21 | is going to have a default arm_count of
2, even though our other instance has a
| | 03:26 | default arm_count of 3.
| | 03:27 | Let's go ahead and say new_person first_
name equals Ethel. And then if we echo
| | 03:36 | back the person first_name and we'll
put a br tag at the end of that and then
| | 03:44 | we do the same thing for the new_
person, we'll able to see that those are
| | 03:49 | different. Let's go ahead and take a
look at that in Firefox, and sure enough
| | 03:53 | there is Lucy and then Ethel. I don't
have a br tag here to keep that nice and
| | 03:58 | clean. I'll go ahead and add it now.
| | 04:00 | So now we can see the difference
between different instances and how each of
| | 04:04 | these objects can be different. Let's
go ahead and add a little more complexity
| | 04:07 | to this. Let's take our hello method
out of here. We don't need that anymore.
| | 04:12 | And instead we'll make a new
function and we're going to call this one
| | 04:15 | full_name. We saw this as an example
earlier. This is a really common use of
| | 04:19 | how we would use object oriented
programming, and for this we're going to
| | 04:23 | return back this first_name and space
and this last_name. So now if we drop
| | 04:35 | back down here, and we say that the new
person's last_name should be Mertz and
| | 04:46 | the regular persons last_name should be Ricardo.
| | 04:54 | Now, instead of asking for person
first_name, let's ask it for person
| | 04:58 | full_name and we'll need those
parenthesis after it. Those parenthesis,
| | 05:02 | remember, are important to let it know
that we're calling a function and not an
| | 05:08 | attribute called full_name. So let's
save that, let's go back over to Firefox,
| | 05:13 | and let's reload it. There we are.
| | 05:15 | So now you can see, how we can
start having attributes and we can start
| | 05:19 | grabbing those attributes and working
with them. Now, we're working with them
| | 05:22 | in a really simple way right here.
We're just taking a first_name and a
| | 05:25 | last_name but we could have a lot of
complexity there where we could grab
| | 05:29 | different pieces, check different
aspects of a class, even look at other
| | 05:33 | classes to find out information about
them, and in the end, turn something
| | 05:37 | back, and then every instance can
return something different because it has a
| | 05:41 | different attributes to it.
| | 05:42 | The last thing I want to leave you
with is that attributes work just like the
| | 05:46 | methods do and we can actually find
out some information about whether they
| | 05:50 | exist or not, whether they have been
defined. So for example, I can say vars
| | 05:54 | equal get_class_vars and person and
that will give me all of the class vars
| | 06:02 | that are defined inside person, and
just like before we can do for each vars as
| | 06:08 | var and the var has a value, if we
want to see what that is, we can actually
| | 06:13 | take a look at the value, and
then echo var and value. There we go.
| | 06:29 | Let's go back over to Firefox and try
that out, I'll just save it Firefox and
| | 06:33 | let's reload, so there they are, we
see what's defined and we also have the
| | 06:38 | Boolean expression same as we did
before. This time we can say echo
| | 06:43 | property_exists and in the person_class
do we have the property first_ name and
| | 06:52 | I'll just do a real simple operator here,
we saw how to do this before, this is
| | 06:57 | nice let me have something really
simple. false. So let's try that out.
| | 07:01 | We go back to Firefox, reload the page
and true, it does exist. So that's how
| | 07:06 | we can also have the Boolean expression.
| | 07:07 | So now we have covered the fundamentals
of object oriented programming. That's
| | 07:11 | really the core what we need to know
that we can define a class, we can put in
| | 07:15 | attributes, we can give it methods, we
can create instances of that class and
| | 07:20 | then we can start putting values in
and out asking for methods to do there
| | 07:24 | thing and that's really all there is to it.
| | 07:27 | Now, there are lot more and
interesting things that we can do besides just
| | 07:30 | these fundamentals, and that's exactly
what we're going to look at in the next chapter.
| | Collapse this transcript |
|
|
4. OOP in PracticeUnderstanding class inheritance| 00:00 | In the last chapter, we looked at
the fundamentals of object oriented
| | 00:03 | programming and specifically, we
learned how to add attributes and methods to
| | 00:07 | class definitions.
| | 00:08 | Now, I want to add a little more
complexity to our classes and start looking at
| | 00:11 | more of the features of object
oriented programming as we start to put into
| | 00:15 | practice. And I want to kick it off
with a discussion of class inheritance.
| | 00:18 | Now, the idea of inheritance is
essential to object oriented programming and
| | 00:22 | basically it's this. We can define
one class and then we can define another
| | 00:27 | class that inherits its behavior
from the first class and when I say it
| | 00:31 | inherits behavior that means it
inherits its attributes and its methods.
| | 00:36 | Let's take a look at how we can do that.
| | 00:37 | So I'm just going to go down to open
up my text editor. I'll do New File and
| | 00:42 | I'm just going to do a quick save on
this. We'll put it in the sandbox and
| | 00:45 | I'm going to call inheritance. There we go.
And I'll just start out my PHP tags.
| | 00:54 | Now we have already seen how to define
the class. So let's just do that real
| | 00:57 | quick. Let's say class Car, and we'll
say that our car has attribute called
| | 01:05 | wheels and it's going to be equal to 4
by default. Another variables it's going
| | 01:10 | to equal to doors. We'll make that
equal to 4 by default, and then let's say a
| | 01:15 | function and we'll just make a silly
function here, we call it wheelsdoors. And
| | 01:21 | that will return this wheels, right we
know how to do that, plus this and arrow
| | 01:30 | doors. So it's going to add those two
together and return it. So like I said
| | 01:33 | it's a silly function but it will at
least make the point for us. And then
| | 01:37 | let's make another class, class CompactCar.
| | 01:41 | Now, we could just go ahead and define
CompactCar, right and we could tell it
| | 01:46 | how many wheels and how many doors it
has. But we can instead use inheritance
| | 01:50 | and say well, actually this is going to
extends car. class car extends car. So
| | 01:57 | if we extend this class then it
inherits, all of its behavior from car. Okay,
| | 02:03 | let's just give this a try, without
doing anything else, let's now say all
| | 02:06 | right we have car1 and that's going to
be equal to a new car, and then I'll go
| | 02:11 | ahead and have car2 and make
that equal to a new CompactCar.
| | 02:15 | So now I have one each of these classes.
So let's say echo car1 and let's find
| | 02:24 | out its number of wheels, and we'll add
our br tag at the end, and it will look
| | 02:29 | nice and pretty. And I'm
just going to copy that line.
| | 02:32 | We are going to also ask for its doors
and we're going to ask for wheelsdoors
| | 02:38 | with the parenthesis right because
this is a method that we're calling, and
| | 02:41 | then let's see another echo br and
then I'm just going to copy all of that,
| | 02:49 | second time and this time
it's going to be for car2.
| | 02:51 | So let's take a look now. If we open
that up in Firefox, we'll go back to our
| | 02:57 | sandbox which is local host and then
the tilde Kevin if you are on a Mac
| | 03:03 | otherwise just btb_sandbox and then
let me put this in inheritance.php. What
| | 03:12 | happens? Notice that both of them
return the same values, right? Wheels 4,
| | 03:19 | doors 4, wheels+doors = 8.
| | 03:21 | CompactCar though it didn't have any
definition. It got all of that from car.
| | 03:26 | That's what inheritance is. And if we
were to go back and change it, so that
| | 03:30 | the doors on car now are 2, and we save
it, reload it, and they change for both
| | 03:35 | as well. At the time that we create the
class in our PHP page, it inherits its
| | 03:42 | behavior from the other one.
| | 03:42 | Now, of course we could change these
values in each instance, right. We could
| | 03:48 | go ahead and say well, actually both
are going to have 4 but then we're going
| | 03:51 | to stop right here and tell car1 that
it actually has two doors. That's still
| | 03:55 | not going to change CompactCar.
CompactCar is still going to have four doors
| | 03:58 | because it's inheriting the default
behavior in the class, not the instance. So
| | 04:03 | it doesn't matter how we push and
pull on different instances of it, right
| | 04:07 | because we can have a red car, and a
blue car and a green car and we can define
| | 04:10 | those all after we create this class.
| | 04:13 | The important part is that CompactCar
takes this definition and just imports it
| | 04:19 | down here into its own body. That's
what the extends does. Now, one of the nice
| | 04:24 | features about inheritance is that
we have the ability to override those
| | 04:28 | characteristic that are in the above one.
| | 04:30 | So we can say well you know what,
everything that's in this CompactCar class
| | 04:34 | should be the same, except the door
should be equal to 2. And now it will
| | 04:38 | inherit everything that's above but
doors will be equal to 2 not 4, all right,
| | 04:44 | we can try that real quick just to
see it. So there is the difference.
| | 04:47 | So it overrides the inheritance and we
can do that for anything. I'll just take
| | 04:52 | function wheelsdoors real quick and
just copy it down here. So, we'll have that
| | 04:56 | in there as well and let's say +100.
So now we go back and we run it, you'll
| | 05:02 | see that it overrides that inherited method.
| | 05:05 | So those are the two fundamental
concepts about inheritance that we need to
| | 05:08 | know is that, one that we can inherit
all of those attributes and methods and
| | 05:12 | two, that we have the ability to
override them, if we don't want to use them.
| | 05:17 | The last thing, I want to do before we
leave inheritance though is to show you
| | 05:20 | a couple of other methods that you can
use, and I'm just going to paste them in
| | 05:23 | here. You'll see I'm using get_parent_
class and I'm using is_subclass_of. Those
| | 05:28 | are two methods that are built into PHP
that will tell me what the parent class
| | 05:32 | of each of these are if it has a parent
or tell me true or false is something a
| | 05:37 | subclass of something else, all right.
So let's just try those real quick and
| | 05:40 | see what they do. So there we go.
| | 05:42 | Now, look at the answers here. So Car
parent. It asks for the parent class of
| | 05:45 | car and came back with nothing. That
means it doesn't have a parent, okay.
| | 05:49 | That's how we know.
| | 05:51 | The CompactCar parent though we asked
it for its parent and it was car. And
| | 05:54 | then on the subclass_of, car is not a
subclass of itself. CompactCar is the
| | 06:00 | subclass of car, but car is
not a subclass of CompactCar.
| | 06:04 | So those are some methods we can use
when we start programming to check and
| | 06:08 | find out dynamically whether or not
something is or isn't a subclass.
| | 06:11 | And I just want to make sure that I at
least show this you so you could draw upon them,
| | 06:14 | if you ever needed those.
| | 06:15 | In the next movie, let's take a look
at another important aspect of object
| | 06:18 | oriented programming, which is how we
can modify, access to our attributes and
| | 06:23 | to our methods.
| | Collapse this transcript |
| Setting access modifiers| 00:00 | In previous movies, we have seen how
we can add attributes and methods and
| | 00:04 | we have seen how we can called those
methods and read and write to the attributes
| | 00:07 | from both inside the class using the
this reference variable and also from
| | 00:11 | outside the class definition.
| | 00:13 | Well, one of the features of object
oriented programming is that we can also
| | 00:16 | restrict access to those attributes and
methods that are inside the class. Now,
| | 00:20 | that's not something we can do when
we're not working with OOP. We normally
| | 00:24 | just have access to a function if it
exists or access to a variable if it exists.
| | 00:28 | Now we have scope that may determine
where the variable exist and whether
| | 00:32 | we can get to it, but that's different.
We're talking about controlling access to it
| | 00:36 | specifically within the class and
we're going to do that with Access modifiers.
| | 00:40 | There are three access modifiers:
public, private, and protected.
| | 00:45 | Public is going to make an attribute or
a method accessible from everywhere.
| | 00:50 | It means anyone can access it anytime
and this can be the default setting for
| | 00:54 | new attributes and for new methods.
We also have private which says that this can
| | 00:59 | only be access within this class, so
we're not able to call a method or an
| | 01:04 | attribute from outside the class like
we did when we were doing some getting
| | 01:07 | and setting of those values or calling
methods that were in classes. We can only call
| | 01:11 | them internally inside the class.
And then protected loosens up just a
| | 01:16 | little bit and it says we can
called them from within this class or
| | 01:20 | the subclasses of this class.
| | 01:22 | So if we're going to be working with
subclasses a lot, we're probably going to
| | 01:24 | want to make things protected so the
subclasses can still work with different things.
| | 01:28 | But if we know for fact it's
only this class, we can go ahead and lock it
| | 01:32 | down tight and make it private and
that way other parts of our code can
| | 01:36 | access it. And don't mistake this
access control for security.
| | 01:40 | We're not restricting what the public can
actually get to on our application. Hopefully
| | 01:45 | they can't get to any of our code or
call any of our methods. They have to
| | 01:49 | interact through the web pages that
we generate and our code on those web pages
| | 01:53 | that they never see, the PHP
code, will have access to these things.
| | 01:57 | So what we're talking about is our code
being able to access different methods.
| | 02:02 | Now why don't we just make everything
public? Well, you could. You certainly could.
| | 02:06 | You could make everything public
all the time. This is good programming
| | 02:10 | practice. It's a good habit to get
into with object-oriented programming to
| | 02:14 | start categorizing whether a method
inside a class ought to be public or
| | 02:18 | private because it will force us to
keep with good programming conventions.
| | 02:23 | But if you decide to make all of your
attributes and all of your methods public
| | 02:27 | all the time, it doesn't give you a
less secured PHP application. It simply
| | 02:32 | means that your objects might not be
as well written as they could be.
| | 02:36 | Let's take a look at how we would each of these.
| | 02:38 | Okay, I'm just going to go into
TextMate and open up a new document and
| | 02:42 | I'll save it in my sandbox. We'll call it
access_modifiers.php. Here we go and
| | 02:50 | I'll go ahead and put my PHP tags on.
| | 02:53 | Now I'm going to start out by just
pasting in some code that will get us
| | 02:57 | started. So I have just got a simple
example class. I have got three variables
| | 03:02 | at the top and I have got a function
that just displays all three of those.
| | 03:06 | Now in order to declare access to
these variables, these attributes,
| | 03:10 | all we have to do is instead of var is
just simply change it to public and this to,
| | 03:15 | let's make it protected and this one
private. So that's all we have to do.
| | 03:20 | We just have to declare them as being one
of these types. So by default if we just use var,
| | 03:26 | that's the same thing as public.
| | 03:28 | So let's take our example class for
a test drive and see how it works. Example =
| | 03:34 | New 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:53 | All right, so let's just try this one
now, public a, see how that works.
| | 03:56 | I'm going to move it a little bit. Let's
open up our Firefox and let's just go to
| | 04:02 | access_modifiers, okay. So it works,
no problem, and it returns one to us.
| | 04:08 | Now let's try the same thing with protected b.
We're going to ask it to return b to us.
| | 04:16 | Okay, let's go back and try it.
Fatal Error: cannot access protected property,
| | 04:22 | so that is exactly what we
would expect. It gives us an error and
| | 04:25 | says yeah, you don't have access to
that because it's protected. Only example
| | 04:30 | and any subclasses of example would have
access. So I'm going to come out to that line
| | 04:35 | and I'm going to then take our a line
again and let's try c. That's going to
| | 04:40 | be private c and we can already guess
what's going to happen. Let's reload it and see.
| | 04:45 | Cannot access a private property,
right? And that also make sense
| | 04:49 | because like protected, only that
class has access to that value.
| | 04:54 | Now to make the point about it
having access, let's try a show abc method.
| | 05:00 | example and show abc. So we'll save it
and we'll go back and let's reload it.
| | 05:07 | You know see it comes back with 123. It was
able to access 1, 2, and 3. It accesses
| | 05:14 | the a because it's public to everyone,
it accesses b because we're inside
| | 05:18 | either the class or the subclass
and c, we're also inside the class.
| | 05:22 | So we're able to get all three of those values.
| | 05:26 | If you like, you can pause the movie
here and try to make yourself a subclass.
| | 05:30 | Let's say small example and it will extend
the class example and then try that out.
| | 05:36 | Create a new instance of it and
see when you run show abc what do you get
| | 05:40 | for that. But I'll leave that as an
exercise for you to do on your own.
| | 05:43 | Now methods have access modifiers just
like attributes but instead of replacing
| | 05:47 | function what we do is we put it
in front of. So public function
| | 05:51 | hello_everyone. That's publicly
available. protected function.
| | 05:55 | I said hello_family is the name of it but
that would be available to anyone in this family,
| | 05:59 | meaning this class or a
subclasses or private where it's only
| | 06:04 | accessible to this class.
| | 06:06 | Now I'll go ahead and add one more method
here just like we did with that show abc.
| | 06:10 | I'll just have a function called hello
that runs all three in a row. So that
| | 06:14 | it will be the first one, then append it
to the second one, then the third one and
| | 06:18 | then return the output. And you will
notice that I put a little comment up there,
| | 06:21 | just reminding you that
functions are public by default.
| | 06:24 | So we don't have to say public. It's
a good practice to go ahead and say it
| | 06:27 | but you don't have to. So let's drop
down and try these out real quick.
| | 06:32 | And I'll just go ahead and paste in a starting
one here, echo, and let me just put in echo,
| | 06:38 | br tag and so we'll do hello_everyone
and that will just call our instance of
| | 06:46 | example and ask it to do hello_
everyone. We'll see what we get back.
| | 06:49 | Let's try that out quick.
hello_everyone gave me back hello_everyone.
| | 06:54 | So let's try the next one, which is hello_
family, and see we get there. Same thing,
| | 07:04 | Fatal call to protected method.
| | 07:07 | And let's go ahead and comment that
out and let's try one more time.
| | 07:12 | We can already guess what we're going to get
I think but hello_me, hello_me and we'll try it.
| | 07:18 | Call to a private method error.
That's not going to work.
| | 07:22 | And then last of all,
let's call that example->hello method.
| | 07:27 | Oh! I have to echo it this time, echo.
There we are. So let's see what we get
| | 07:32 | back this time. hello_everyone, hello_
family, and hello_me, all of those came
| | 07:37 | out of that hello method because
it has access to all three of them.
| | 07:40 | So you stop and think about it for a
second, what we have done is restrict access
| | 07:44 | to certain functions and attributes
from outside of our classes,
| | 07:50 | but at the same time we're still able to
get access to those, but we have to do it
| | 07:55 | through another route, okay. We have to
go through a side door and that concept
| | 08:00 | is what I want to talk a little
bit more about in the next movie.
| | Collapse this transcript |
| Using setters and getters| 00:00 | In the last movie, we started out our
discussion of access modifiers. The last
| | 00:05 | example we're looking at, let me do something
that I want to dive a little bit deeper in.
| | 00:09 | If you remember back, even though we
didn't have access to the private and the
| | 00:12 | protected methods inside the class,
we did have another method that was
| | 00:16 | publicly accessible, hello and it
did have access to those private and
| | 00:19 | protected methods.
| | 00:21 | It's a little bit like a bank.
We can't just walk into a bank and go into
| | 00:24 | the bank vault and either put money in
or take money out. We have to go see the
| | 00:28 | teller first. The teller can go to the
bank vault for us and put cash in or out
| | 00:33 | but we're restricted from going in
ourselves. This type of access setup is very
| | 00:37 | common in object-oriented programming,
so I think it's worth looking at a
| | 00:40 | little closer and we can refer
it to as Setters and Getters.
| | 00:45 | Those are two very strange words but
what we're talking about is methods which
| | 00:49 | set something and methods which get
something. So setting a value and getting a
| | 00:53 | value. In general, what we're
talking about is working with attributes or
| | 00:56 | perhaps with databases.
| | 00:58 | To sit closer with Setter methods and
Getter methods and to start this off from
| | 01:02 | this discussion, I'm going to just
paste in a simple class. I call up this
| | 01:07 | SetterGetterExample class and you will
see that it has an attribute a and a by
| | 01:13 | default is 1 and it's private. So we
cannot access it from outside the class.
| | 01:17 | We have already seen how we try to
create a new instance of it and then access
| | 01:21 | a like this that it will fail for us.
That won't work; it is restrictive.
| | 01:25 | However, we can have a Getter method
which I have called get_a and it's public
| | 01:32 | and we have access to it and it has
access in term to the private value of a.
| | 01:38 | So it's a lot like our bank teller, we
can walk into the bank but we can't go
| | 01:42 | in the vault directly, it's private.
But we can go to the publicly available
| | 01:47 | teller, who can then in turn
go into the private vault area.
| | 01:51 | And then the second method is the
Setter, set_a and it takes a value as an
| | 01:56 | argument and all it does is set the
value of a equal to that value. So let's
| | 02:01 | try our Getters and Setters out.
| | 02:02 | I am just going to simply echo back
the value of get_a so that it should be 1
| | 02:08 | and then I'm going to set it to the
value 15 and get it again, just to make
| | 02:11 | sure that it's working. Let's save that
and we'll go back to Firefox and we'll
| | 02:15 | just load up access_modifiers2. So
there we're 1 and 15 that it will return. So
| | 02:21 | those are Getter and Setter
methods and that's how they work.
| | 02:24 | Now you may be wondering why go to all
these trouble, why write all these extra
| | 02:28 | code, when we can just simply declare a
as being public and then we could work
| | 02:31 | with like a normal variable and we can
set values and get values directly to
| | 02:36 | the variable. But the reason why is
like our bank teller example because the
| | 02:40 | bank teller serves a very useful purpose.
They check and make sure we're who we ay we are,
| | 02:44 | sand they check and make sure
that our account has the right amount
| | 02:47 | of money in it before we make the
withdrawal. They may also initiate some other
| | 02:50 | actions before they finish with our transaction.
| | 02:53 | So, for example, the bank teller might
make a note about how many withdrawals
| | 02:57 | have occurred for the day. In the case
of our about application, it's the exact
| | 03:00 | same thing. We can perform other
actions before we return that value.
| | 03:04 | So let's say that we had an action that
was something like log_users_ip_address
| | 03:11 | and we have to write that function, but
this could take place before we let any
| | 03:15 | one get that value out of there. Or we
could check and make sure that they were
| | 03:18 | logged in as an admin user perhaps,
before we get that value. Maybe only admins
| | 03:22 | are able to get that value back.
| | 03:24 | Now there are some PHP developers who
prefer to make most of the attributes,
| | 03:28 | private and protected, and then
control access to them through methods like
| | 03:32 | this. I'm not one of them. I use
Setters and Getters but I do it when
| | 03:36 | necessary, when I need to intervene in
the process either to take care of some
| | 03:40 | other business before we return the
value or set the value or when I need to do
| | 03:44 | some kind of an access control or something
like that before getting to the value.
| | 03:48 | Otherwise, I go ahead and just make it
a public attribute and that's how we'll
| | 03:51 | be doing it throughout this tutorial.
But I'll leave it up to you to decide
| | 03:53 | which one you are most comfortable with.
| | 03:54 | Now that we have seen the three Access
modifiers, I want to take a look at the
| | 03:58 | different kind of the
modifier in the next movie.
| | Collapse this transcript |
| Working with the static modifier| 00:00 | In addition to the three access
modifiers that we have just learned, there is
| | 00:03 | another modifier that we should talk
about and it is with the keyword static
| | 00:08 | and it's a static modifier. We can
modify an attribute or function with it and
| | 00:11 | we can used it even in conjunction
with all three access modifiers, so really
| | 00:16 | it's different because
we can used both together.
| | 00:18 | Let me give you an example of its usage
in the class and then we can talk about
| | 00:21 | how it works. So, an example of using
in the class would be like this. You have
| | 00:25 | a class student and it has a variable
total_students and I have declared it's
| | 00:31 | being static, then I have got function
welcome_students which is also declared
| | 00:36 | as being static. So what is static?
| | 00:38 | Well, if you remember back to Chapter 2,
when we were talking about function
| | 00:42 | that had static variables and then we
use them like a counter inside there
| | 00:46 | because we said that they would stick around.
Well, this kind of works the same way.
| | 00:49 | Now, standard attributes in the class
stick around as long as the instance is around.
| | 00:54 | But with static, the big difference,
if to the attribute or the method,
| | 00:58 | is around even if there is not an
instance. Let me just repeat that one more
| | 01:03 | time to make it clear, we have access
to both total_students and the method
| | 01:08 | welcome_students even if we don't
have an instance. It breaks the rule that
| | 01:13 | we're talking about earlier when
we're talking about creating instances in
| | 01:16 | order to have these things, static
allows us to do that because the static
| | 01:19 | variable is tight to the
class itself not to an instance.
| | 01:24 | In other object-oriented languages,
this is often referred to as class method
| | 01:28 | or a class attribute. Now in PHP, we
just simply call it Static. We say it's a
| | 01:33 | static method or static attribute.
Because we don't need to create an instance,
| | 01:37 | the way that we refer to them is a
little different because we need to specify
| | 01:40 | which class we're talking about, so we
need to first say what class, when we do
| | 01:45 | with an instance we have created,
that class, we have an instance of that
| | 01:48 | class. So everything is
directed to the direct place.
| | 01:50 | But we need to be specific. What if
we had two classes they both had an
| | 01:53 | attribute called name? How do we
know which one we're talking about?
| | 01:56 | So we'll need to specify student and
then instead of the arrow notation which
| | 02:03 | is used for instances, we're going to
used two dots. And we'll talk a little
| | 02:07 | bit more about these dots in the next
movie. For now, just note when we're not
| | 02:11 | dealing with an instance, we use
the two dots and then the $ sign
| | 02:16 | total_students.
| | 02:19 | And just so that you can really compare
the difference, what we normally would
| | 02:22 | have is something like student = new
student and then we would be able to say
| | 02:29 | echo student and then whatever value.
Let's say it was total_students, let's
| | 02:36 | say that that was a non-static method.
Now that's what it would normally look like.
| | 02:41 | So if you notice here, this call
knows where to go find its code because it
| | 02:46 | knows what class it belongs to. So it
knows where total_students is located.
| | 02:52 | But if we don't have an instance, then
we also need a way to tell PHP where it
| | 02:58 | can find this variable, right, we
might have a lot of classes and if the name
| | 03:02 | of the variable something like first
name, how does it know where to go find it,
| | 03:05 | how does it know which class to
look at. So we're going to need to
| | 03:07 | reference the class.
| | 03:09 | And then because we don't have an
instance we use two dots instead of the
| | 03:14 | arrow, okay. We'll talk a little bit
more about those two dots. But for now
| | 03:18 | instances are going to use that arrow
notation right, -> and then instead,
| | 03:26 | we're going to say total_
students after the two dots.
| | 03:30 | So take a second and notice the
differences there, notice the $ sign is here,
| | 03:34 | there was not a $ sign here. This is an
instance, this is a static call, okay,
| | 03:40 | so let's go ahead and just try that
out so that you can see it working.
| | 03:44 | Go into Firefox and we'll open up static
_modifier, there we are, it comes back
| | 03:51 | with 0 which is the value of students,
and then let's go ahead and just put br
| | 03:57 | tag at the end and then we
could do the same thing with echo
| | 04:02 | Student::welcome_students
and we'll do our br tag again.
| | 04:11 | And that's how we call a method, still
with the double parenthesis after but
| | 04:15 | also still using these two colons in
between the two. If we do that you will
| | 04:19 | see that that comes back just as well.
| | 04:22 | And we can work with this just like we
would with normal values, you see here
| | 04:25 | that I have done welcome_students and I
have passed in greetings as a variable
| | 04:29 | to it. You will see here that I have
got a student, I set it equal to 1 and
| | 04:34 | then student total_students, so they
work just like normal attributes and methods.
| | 04:40 | Now the other thing that's really
different about working with static methods
| | 04:44 | is that because it's not an instance,
we can't use this. So normally we would
| | 04:49 | do something like this. It's a public
function add_student and then we would
| | 04:53 | increment it this way. But we can't do
that, we don't have access to this. In
| | 04:57 | fact, I'm going to put a note up here
at the top that says with static methods
| | 05:03 | you can't use this. Okay and
this can be a good reminder for us.
| | 05:11 | So instead we need another way to
refer to this so I'm going to make this
| | 05:15 | method static also. So since we can't
use this, we can still use this double
| | 05:21 | dot notation. There we go student::
total_students and then we need a $ sign
| | 05:25 | too. So that will actually reference
the correct value for total_students.
| | 05:31 | Now you may be wondering, do we need
static in front of this one? Can it just
| | 05:35 | be a public method? It's best for
you keep your static attributes in your
| | 05:38 | static methods completely separate from
your instance methods, the normal ones
| | 05:44 | that are working, the non-static ones.
That's how they are meant to be used, as separately.
| | 05:48 | In fact, if in your PHP error settings
in php.ini, if you had it set to strict,
| | 05:54 | it will complain if you call a non-
static method in a static context. In other
| | 05:59 | words, you start mixing between them
and you have a static method, they call
| | 06:02 | something that's non-static and
so on. You'll start getting errors.
| | 06:05 | So in general, all the static methods
go together, they only call other things
| | 06:10 | that are static, all of the non-
static ones belong to instances and you can
| | 06:14 | make reference to them. That doesn't
mean that you can't ever use them;
| | 06:17 | you just have to be careful about how you do it.
| | 06:20 | The last point that I want to make
is that static variables are shared
| | 06:24 | throughout the inheritance tree. Take a
look at the code that I just pasted in
| | 06:27 | there. I just have got a simple classes
called One, Two, and Three. There is a
| | 06:31 | static variable called foo that gets
inherited into all three of them and I
| | 06:35 | just set a couple of values
for foo, One, Two and Three.
| | 06:37 | So if you echo those back what will the
results be and the answer is three for
| | 06:43 | all of them. Now that may be a little
bit counter intuitive, you may think that
| | 06:47 | each class should have its own but
that's not true, it's define once and
| | 06:52 | whenever we talk to class Two, it
actually is referencing that same static
| | 06:58 | value that's in class One. So just be
careful about that because that trips a
| | 07:02 | lot of PHP developers up.
| | 07:04 | So I'm just going to save it and just
try one last time, just to make sure
| | 07:07 | we do get those 3s at the bottom and that
shows that these static variables are
| | 07:11 | shared between parents and their children.
| | 07:13 | So you might be so wondering when would
you use static variable and methods and
| | 07:18 | it's when you don't actually have an
instance. Let's say that we're talking not
| | 07:22 | about a particular student but about
the total number of students that have
| | 07:27 | been created. That would be
something that we can keep track in a static
| | 07:30 | variable. We might also have
some very basic class information.
| | 07:34 | Let's say that we wanted to keep these
student types in there and we might have
| | 07:38 | freshman, sophomore junior, senior as
being the different types of students
| | 07:42 | that could be chosen. That could be
in the static method that we would have
| | 07:46 | access to all the time. The student
class could report back to us about what
| | 07:50 | kinds of students there could be
even if we don't have a students.
| | 07:53 | Now I have said earlier that we would
talk a little bit more about these double colon.
| | 07:57 | Let's do that in the next movie.
| | Collapse this transcript |
| Reviewing the scope resolution operator| 00:00 | In this movie, I'm going to take a
little closer look at something called the
| | 00:03 | Scope Resolution operator. We saw it
in the last movie when we were working
| | 00:07 | with static variables and static
methods and it's those two double colons.
| | 00:11 | That's what it is, the Scope Resolution operator.
| | 00:14 | Now in PHP it also has a much
bigger fancier name, which I'm sure I'll
| | 00:17 | mispronounce Paamayim Nekudotayim.
If we break that down, it's Hebrew and
| | 00:25 | it means One Doubled Dot Doubled.
So one doubled dot and then doubled again and
| | 00:30 | that's why we have two colons. So
that's the double colon in Hebrew.
| | 00:33 | Now why should you care what it's
called in Hebrew? Because that's what PHP
| | 00:37 | calls it internally. If you remember,
PHP was developed by Israelis. Sometimes
| | 00:42 | you will get an odd error, it will
say Parse error, syntax unexpected T and
| | 00:47 | then you will get this long word and
you are like what in the world is that thing?
| | 00:51 | I have no idea what went wrong
in my code. Well, in English, that error
| | 00:56 | means that you screwed up the
reference to an object or to its scoped
| | 01:00 | attributes or methods. Let me show
it to you so you will recognize it.
| | 01:03 | Here I am in the same static modifier
page that we were just working in. You can
| | 01:08 | put this anywhere but I'm just going
to make a bogus request here. I'm just
| | 01:11 | going to say $make::an_error, there
we go, and that's not going to work, right?
| | 01:19 | For all sorts of reasons,
that's wrong. Let's try and load that up.
| | 01:23 | There we are. Now we see the error,
unexpected double colon. So that's what
| | 01:28 | it's telling us and so what it lets us
know is we screwed up the reference.
| | 01:32 | So you can think of the Scope Resolution
operator as steering PHP to the right
| | 01:36 | place to find a variable. Where is
the scope for this thing? It's inside a
| | 01:40 | certain class. If you think about it,
a static class variable works pretty much
| | 01:44 | like a normal variable as long as we prefix it
with a scope. We saw that in the last movie.
| | 01:49 | It's just a variable that's being
maintained in a class. The class is its
| | 01:53 | scope. Keeping the class on a specific
scope helps to keep it conflicting with
| | 01:57 | other variables. So, for example, we
can have this Student::$total_students but
| | 02:03 | we could also still have something
like $total_students = 20 and that's a
| | 02:09 | separate counter. That's a separate
variable that we're working with, because
| | 02:12 | it has a different scope.
| | 02:14 | So because they stick around all the
time thinking of these variables as being
| | 02:19 | normal variables but just with a
certain scope might also help you to remember
| | 02:23 | that you still have to put the dollar
sign in front of them, which we didn't
| | 02:25 | have to do in the instance variables.
| | 02:27 | So that's just a little more insight
into what these double colons are and also
| | 02:31 | a heads-up for when you get this crazy
error message, what does it mean?
| | 02:35 | It means that you have used double colon
someplace and you made a bad reference.
| | 02:40 | It could not find the code that you
were looking for, the scope was wrong.
| | 02:43 | Now that we know a bit more about the
Scope Resolution operator, let's look at
| | 02:46 | how we can use it to reference
an instance's parent as well.
| | Collapse this transcript |
| Referencing the Parent class| 00:00 | In the last movie, we talked a
little bit more about the Scope Resolution
| | 00:03 | operator, those two double colons. In
the movie before that, we talked about
| | 00:07 | how to use the Scope Resolution
operator to reference the static attributes and
| | 00:11 | methods inside of our class. In this
movie, I want us to look at how we can use
| | 00:15 | that same Scope Resolution operator
when dealing with inherited classes, how
| | 00:19 | subclasses can refer to methods
that are in their parent class.
| | 00:23 | So I'm going to open up TextMate and
I'll just open a new window and save it as
| | 00:29 | parents.php in my sandbox and we'll
start out with our PHP tags. Now I have
| | 00:35 | already got a real simple class here.
This is what we were looking at a couple
| | 00:38 | of movies ago where I have got a static
attribute and a static method in there
| | 00:42 | and $a = 1 by default and then
modified_a just simply adds 10 to it.
| | 00:46 | Now we talked about the Scope
Resolution operator and we also talked about self
| | 00:50 | and how self is a keyword that just
simply means $a. So we can use either one.
| | 00:56 | It's convenience method that allows us
to just simply refer to whatever this
| | 00:59 | class is. That's the
attribute that we want to look for.
| | 01:02 | So since we understand that, let's now
talk about inheritance and we know that
| | 01:05 | if we have a simple class like B that
extends A that it inherits those methods
| | 01:11 | that are in A. So that includes those
two static methods. So already we know
| | 01:16 | that we could do something like this
and it would work for us. Let's save it
| | 01:19 | and let's just try it out to prove to
ourselves that we can still access a and
| | 01:22 | modified_a by simply looking into the class B.
| | 01:25 | We will go into Firefox and
instead of static_modifier let's load up
| | 01:30 | parents.php. So there it is. It
pulled back those two values, 1 and 11. Now
| | 01:35 | what I want us to understand here is
how we can reference the attributes and
| | 01:40 | methods that are inside A from inside B.
So here I've put in two simple tests,
| | 01:45 | they are also static methods. The
first one I have just called attr_test for
| | 01:49 | attribute test and the second is a
method_test. And each one is going to refer to A.
| | 01:54 | Now this shouldn't be any surprise,
just A::$a. Now we also could refer to B
| | 02:01 | and get the same value back, right?
Because it is also inherited, those would
| | 02:04 | both work. Well, we also have the
ability to call parent. That's the other
| | 02:09 | keyword that I want us to see and we
can ask it to return the value that it
| | 02:13 | finds in its parent, in A.
| | 02:15 | So let's go ahead and try this out
and then we'll talk about why this is
| | 02:18 | important. So I'm just going to put in
two more tests here, these are going to
| | 02:21 | call my new test methods that I have
written up. So I'll just save it, we'll go
| | 02:25 | back and we'll reload and you
will see that it still works.
| | 02:28 | So just like self, parent becomes a
convenience method that we can use to refer
| | 02:33 | to whatever the parent's attributes are.
Now up until now, I have been really
| | 02:37 | trying to stress the difference between
static or class methods and attributes
| | 02:42 | and instance methods and attributes
when we actually have an instance of something.
| | 02:46 | Well, the odd thing about parent is
that it breaks down that division. It
| | 02:51 | totally violates all the rules I have
been telling you. Up until now you could
| | 02:54 | safely say well, use the double colon
whenever you are talking about something
| | 02:58 | that's static and we could just
associate the two, ::static. Then we would use
| | 03:03 | the $this whenever we were talking
about an instance. So we would have those
| | 03:07 | two different ways to work
depending on which one we're working with.
| | 03:10 | But with parent, we can use it with
instances too. In fact, it's important to
| | 03:15 | be able to use it. What's even
weirder is that it only works with parent
| | 03:18 | methods, not with parent attributes.
If you think about it, it makes sense,
| | 03:23 | because let's say, for example, we
have $object = new B. So we create an
| | 03:27 | instance of B and it instantiates all
of its aspects, but A still hasn't been
| | 03:33 | instantiated. So we can't really
refer to attributes that are there. We can
| | 03:38 | look up what the methods would be but
we don't have attributes because it's not
| | 03:42 | instantiated.
| | 03:43 | So I realize that this may seem a
little confusing because it is breaking those
| | 03:46 | rules. So let's see how it works and I
think it will become clear. I'm going to
| | 03:49 | add a new method here, something real
simple, a public function called hello,
| | 03:53 | and it's just simply going to
echo back hello to us, super simple.
| | 03:56 | Now we know that in our class B, we
could have another public function
| | 04:01 | instance_test that's going to expect
us to have an instance and it's going to
| | 04:04 | look for this hello and hello will be
inherited by b. Let's go ahead and try
| | 04:09 | that out. So I'll come down here and
let's just say instance_test. Let's go
| | 04:13 | back and reload it and sure enough
there it is. We get Hello returned back to us.
| | 04:18 | So what I'm telling you now is that we
actually can do this. parent::hello
| | 04:24 | and we'll save it, we'll go back and
we'll reload it. You will see that it
| | 04:27 | still works, both of us work for us,
not just this, but also parent.
| | 04:33 | Now why would we ever want to do this?
Why do we ever still want to have access
| | 04:39 | to both this hello and the parent's
version of hello? Well, it actually can be
| | 04:44 | really useful to be able to refer
things back to the parent to find out how
| | 04:50 | the parent would handle it in addition to be
able to find out how this class would handle it.
| | 04:54 | Let me give you a super simple example,
I'm just going to override hello in the
| | 05:00 | B class. So instead of hello being
inherited, it's been overridden now. So take
| | 05:05 | a second to look at it, pause the movie
if you need to, but I want you to think
| | 05:08 | about what it will do if we now call
object hello. So we're calling it on B as
| | 05:13 | an instance method of B. The first
thing it is going to do is it is going to
| | 05:17 | call this echo statement. Then it's
going to call the parent method hello and
| | 05:24 | do whatever is there and then it
will do another echo statement.
| | 05:29 | That's the idea here, we're in the
class we've overridden, but we still have
| | 05:33 | access to the old overridden class.
That's extremely useful. We could have it
| | 05:39 | return a value to us. We could say,
for example, see if the parent class is
| | 05:42 | able to find a record in the database.
If it is not, then I'll try and handle
| | 05:47 | it or vice versa. We could say well,
let class B look for something in the
| | 05:51 | database and if it's unsuccessful, then
ask class A if it can find something in
| | 05:56 | the database. We can still access
those old behaviors by using this parent notation.
| | 06:01 | So let's try it out just to prove that
it worked. So there it is. You will see
| | 06:05 | that it did the asterisk, then went to
the parent method, returned hello and
| | 06:09 | then did the asterisk right after it.
So to sum all of this up and make it
| | 06:13 | really simple for you, when you are
working with static methods, go ahead and
| | 06:16 | use this parents method with these
double colons. That's when you should use it,
| | 06:20 | just like we were following in the
rules. But the only time that you should
| | 06:24 | use it with instance methods is when you are
trying to actually access the parent method.
| | 06:31 | In this case if we don't actually mean
that we want the parent, then we could
| | 06:35 | just do this hello instead. So use
this when you are working with instances
| | 06:41 | expect for this one case. In the next
movie, let's look at constructors and
| | 06:46 | destructors when working with classes.
| | Collapse this transcript |
| Using constructors and destructors| 00:00 | In this movie, we're going to
look at constructors and destructors.
| | 00:03 | Constructors and destructors are
special methods that automatically get called
| | 00:07 | whenever an object is created or
destroyed. So the idea is that whenever an
| | 00:11 | object is created, stop while
constructing it and perform the construct method
| | 00:17 | and whenever we're destroying an object,
stop and do the destruct method as well.
| | 00:22 | Let's go into depth on constructors
first, because they are far more useful.
| | 00:26 | Constructors are going to be ideal for
any initialization or housekeeping that
| | 00:30 | an object may need before it's
actually going to be used. Now in PHP 4.0,
| | 00:35 | constructors were methods that had the
same name as the class. Now, of course,
| | 00:38 | we're not using PHP 4.0 here, but I
want you to see it, just so that you are
| | 00:41 | familiar with it and if you are
looking at some old code you will recognize
| | 00:45 | that and know that that's what it is.
It has the exact same name, the class is
| | 00:48 | table, so the function is
called table. That's a constructor.
| | 00:51 | Now to give it a better name in PHP 5.0,
it is __construct and that's how we're
| | 00:57 | going to name the constructor and that
is going to be the automatic method that
| | 01:01 | will get performed whenever an
instance of class Table is created.
| | 01:06 | Let's see how it works.
| | 01:07 | I am just going to open up TextMate and
start a new window and we'll do Save As
| | 01:13 | constructors. Even through we're going
to talk about destructors, I'm going to
| | 01:17 | go ahead and just call it constructors
for now, php tags. So let's start with
| | 01:22 | that class that we were
just looking at, Table class.
| | 01:24 | So here we can see more clear. That's __
construct and this is our chance to do
| | 01:29 | some housekeeping. So let's say just
as a really simple example that we had a
| | 01:33 | public 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:46 | Let'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:01 | Let's bring that up in Firefox and try
it out. Constructors, there we are. So
| | 02:07 | this has the exact same effect, of
course, as if we had put legs = 4, but
| | 02:11 | imagine that we wanted to do
something much more complex than that. Imagine
| | 02:15 | that we maybe wanted to stop and
check a database or that we wanted to do a
| | 02:20 | little bit of research into the
state of other classes and their static
| | 02:25 | variables and things like that.
| | 02:26 | If fact, I'll give you another real
simple example that we can look that. Let'
| | 02:30 | say that we had static public and then
let's keep track of total tables as a
| | 02:36 | static value. We'll set it to zero to
start with. So now whenever we create a
| | 02:41 | new table, let's increment that
value, Table::$total_tables++.
| | 02:49 | So that's going to increment it every
time we create a new instance, the class
| | 02:53 | is going to keep track of how many
total tables have been instantiated.
| | 02:58 | Let's give that a whirl. Let's just come
down here and I'll paste a couple of usages
| | 03:03 | of this so we can just see it.
| | 03:04 | I am just going to simply echo back the
value, it should be zero here, and then
| | 03:08 | I'm going to create a new table and
then echo that value back and then I'll
| | 03:11 | create another new table and I'll echo
the value one more time. So let's just
| | 03:14 | try that. Oops! It came back actually
it was 1 here because we had already
| | 03:20 | created the table back up there. So
this will actually be 1 the first time.
| | 03:24 | Again, this is a really simple example
but you can now see how we can begin to
| | 03:29 | actually take care of some business
each time one of these objects is created.
| | 03:32 | I'm not going to go into the full
example, but if we had this as a subclass,
| | 03:37 | let's say extends Furniture and then
down in our construct method we could
| | 03:42 | refer to the parent method construct.
| | 03:48 | So now once we have done all of the
construction that's involved with the Table
| | 03:53 | class, it will jump up to the
Furniture class to see if there is any
| | 03:56 | constructing that needs to take
place there. We saw that parent Scope
| | 04:00 | Resolution operator allows us to do
that. But again I'm not going to go ahead
| | 04:04 | and fully implement that, I just
wanted to point out that it was possible.
| | 04:07 | The last point I want to make about
constructors is it they also can take
| | 04:10 | arguments. So, for example, $leg_
count and I can say = 4 and then I'll just
| | 04:16 | take $leg_count here and set it equal
there. Now, notice that I have a default
| | 04:22 | value for 4. If I did not have that,
then every time I create a table I would
| | 04:26 | need to pass in an argument here 4, 5, 6 so on.
| | 04:31 | It's going to be expecting me to
pass an argument just like I would to a
| | 04:34 | function. I'm going to pass it in to
those parenthesis that are after the class
| | 04:38 | name. That's why those parenthesis are
there, in case you are wondering, it's
| | 04:42 | what we're passing into the construct method.
| | 04:44 | It's always a really good idea to give
a default value there just so that if
| | 04:48 | you ever do create a table without one,
that it doesn't give you an error and
| | 04:52 | it's doesn't say hey, wait a minute,
I was expecting an argument and I got
| | 04:55 | nothing. So even if the argument is
null or zero or something like that, go
| | 04:59 | ahead and give it some default
to fall back to for constructors.
| | 05:03 | Now, constructors are going to be
really useful powerful tools, destructors not
| | 05:07 | as much. Here is what it looks like,
it's __destruct and then two parenthesis
| | 05:12 | just the same and then we could have
it do something. I would have it say
| | 05:15 | $total_tables--.
| | 05:17 | Now the reason why it's not that useful
is because most of the time we just let
| | 05:22 | our objects stick around that we have
instantiated through the entire request.
| | 05:27 | So if the user hits a page, it goes
and creates all the objects it needs. It
| | 05:30 | generates the page for the user and
then PHP destroys everything. It doesn't
| | 05:35 | hang on to those objects. It doesn't
keep them around. They all get destroyed
| | 05:39 | and the destruct method does get called
then, but it kind of doesn't matter at
| | 05:42 | that 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:50 | The one time it is useful is that you
can call it directly if you are going to
| | 05:54 | destroy an instance. So that's why it's
there, it's not used that much. I would
| | 05:58 | say it's used 1% as often as you are
going to use constructors, but at least
| | 06:02 | you know what it is. So spend a little
bit of time playing with constructors
| | 06:06 | until you get comfortable with them.
In the next movie, we'll look at cloning objects.
| | Collapse this transcript |
| Cloning objects| 00:00 | Now that we have seen how to create
objects and specifically how we can use a
| | 00:04 | constructor method on those objects, I
think it's time for us to now talk about
| | 00:07 | how to copy objects. We call that
cloning. I'm going to TextMate, I'll open up
| | 00:12 | a new window and let's just save this
as cloning.php and we'll go ahead and
| | 00:19 | start our PHP tags.
| | 00:21 | Now in our earlier discussion about
references, I noted that all objects use
| | 00:25 | reference assignment, by default. So,
for example, if we have a class called
| | 00:28 | Beverage which just has one attribute,
name, then we can create a new Beverage,
| | 00:34 | assign a value to name. Then if we say
$b = $a and we change the value of b's
| | 00:39 | attribute name, it will also change
the value of a's name because it's a
| | 00:44 | reference. Let's just try that to
just make sure we remember that.
| | 00:47 | I am going to open up Firefox and
we're going to look up cloning, tea.
| | 00:52 | So you see coffee got disappeared.
Tea became the new value for a because
| | 00:56 | their reference is pointing at the same object.
But what about when you don't want it to be
| | 01:00 | a reference? What about when you
want to actually make a copy of it?
| | 01:03 | How do you actually copy that object over?
| | 01:07 | And the way that we do that is by
using clone. So clone $a will then make a
| | 01:13 | copy of it. So now when I say $c->
name = "orange juice", then echo back the name,
| | 01:22 | we can see what that's going to return for us.
I'm going to need a <br> tag in here.
| | 01:26 | All right, let's try it now.
| | 01:30 | Back over here, you will see that a is
still equal to tea, the value of that
| | 01:34 | didn't change. If we want to just check
it, we can also just ask what the value
| | 01:37 | of c is and I'll just move this <br>
tag down here again. So there we go, now
| | 01:43 | you can tell that changing the name of
c did change it because it was a copy.
| | 01:49 | But it did not have any effect on a
because it is no longer a reference. For b,
| | 01:53 | that wasn't true. They were
references to the same thing.
| | 01:56 | I think that should be self-explanatory
enough. The other important thing about
| | 01:59 | cloning and using that clone is if you
remember we had the construct keyword.
| | 02:02 | So here is a real simple construct
method that will get called automatically.
| | 02:07 | Whatever housekeeping is done in that
construct method is not done when we clone it.
| | 02:12 | It's only when we create a new and
not when we copy it, instead, we have a
| | 02:16 | clone method, __clone. So whenever
this object is cloned, then do this next
| | 02:23 | step. Let's just try this with the
same beverage and just see what happens.
| | 02:26 | Let's make sure I have got some <br>
tags, I do. So the first time that
| | 02:29 | we create the object and we assign it to a,
we get "This new beverage was created."
| | 02:33 | Then when we make a reference with b,
nothing happens, because it's just a
| | 02:37 | reference. It's not until we get down
here and we actually make a clone that
| | 02:41 | clone method gets called. So that
automatic clone method is going to work just
| | 02:45 | like a constructor and it's going to be
your opportunity to do the same kind of
| | 02:48 | housekeeping whenever you clone an object.
| | 02:50 | So now that we know how to make both
references to objects and how to clone
| | 02:55 | objects, in the next movie, let's talk
about how we can compare objects to be
| | 02:58 | able to tell whether or not
it's a reference or a copy.
| | Collapse this transcript |
| Comparing objects| 00:00 | The cloning that we discussed in
the last movie presents us with
| | 00:03 | a great opportunity to talk about comparing
objects. This is how we can tell if we have
| | 00:07 | two objects with the same reference
or two objects that merely look alike.
| | 00:11 | There are two operators we can use to
compare objects. There is the normal
| | 00:15 | Comparison operator, which is just
equals equals, or there is the stricter
| | 00:19 | Identity operator, the equals equals
equals. Now don't worry if you don't
| | 00:23 | remember the name Identity operator.
What is important is that it is a stricter
| | 00:27 | form of comparison. So in the first
case it's going to compare whether
| | 00:30 | the two objects have the same attributes,
whether or not they are basically the same.
| | 00:35 | But the stricter Identity operator is
going to require that the two objects
| | 00:38 | compared actually point
with the same reference object.
| | 00:41 | I am going to go to TextMate,
I'll open up a new window and let's just save
| | 00:46 | this as comparison.php and we'll go
ahead and start with our PHP tags.
| | 00:55 | Now let's imaging that we have a real
simple object. I'm just going to call it Box
| | 00:59 | and I'll just give it a simple attribute
called name. So let's make a reference
| | 01:03 | to the box first of all. So, that's
just a real simple reference assignment and
| | 01:07 | we know that always takes place with
objects. Then now that we know how to do a clone,
| | 01:12 | let's also do a clone version of it,
just so that we can see that.
| | 01:16 | Then just so that we can compare that to
something else, let's now make another one
| | 01:20 | called box changed, okay. So just be
clear, this is something different.
| | 01:23 | We're cloning it again, but this time
we're just going to change one of its attributes.
| | 01:27 | Then last of all, let's just
make another box, which is a
| | 01:30 | completely separate instantiation of new box.
| | 01:35 | So now that we have these different
instances to work with, now let's just try
| | 01:38 | writing ourselves some simple tests.
I'm going to paste in the tests I have
| | 01:42 | already written just to save me time from
typing. You can pause the movie be if
| | 01:45 | you want to copy them down to work along with me.
hat I'm simply going to do on each one
| | 01:49 | is echo back true or false depending
on the resolves of the equals operator, ==.
| | 01:56 | So I'm going to compare box with box
weapons, box with clone, box with change,
| | 01:59 | and box with the another box and that
will then give me a comparison to say
| | 02:04 | in which cases is this true,
when are they the same,
| | 02:06 | and we'll be able to see the difference.
Let's bring that up and try it.
| | 02:09 | I will go to Firefox and let's bring
up comparison.php. So I got true, true,
| | 02:16 | false, and true. So let's just come
back here and make ourselves some notes.
| | 02:20 | This is true, this one was also true,
this one was false, and this one was true.
| | 02:28 | So, let's look at what happened
there. The reference is still equal.
| | 02:32 | They point to the same thing, their
values are the same. The clone, also equal.
| | 02:37 | Even when though they don't point to
the same object, the attributes are the same.
| | 02:40 | They start out with the name just
being box. So there is no difference.
| | 02:44 | It says, yeah they are the same.
| | 02:46 | Box_changed is the one that's false,
and the reason why is because the
| | 02:49 | attribute name got changed. It's now
changed box. So, it returns false and
| | 02:54 | even when we compare box with another box,
a completely new instance,
| | 02:57 | which is basically the same thing as when
we did the clone version, it comes back true,
| | 03:01 | because the attributes are essentially
the same. It's pretty much the same thing.
| | 03:06 | Now let's try those tests again,
but this time we're going to do with
| | 03:09 | the stricter Identity operator. So,
equals equals equals. You can actually just
| | 03:13 | copy and paste that top text again and
then just go in and change each of those
| | 03:17 | to be ===. And let's try that
and see what that does.
| | 03:20 | We will come back, reload. I put an
extra br tag in here so I could separate them.
| | 03:24 | Notice only the first one is true;
the rest are false. So, I'm just going
| | 03:28 | to add my notes here. That's true and
the rest of them are false.
| | 03:37 | The only one that passed the test was the
reference. They point to the exact same thing.
| | 03:43 | When we cloned it? No, not the same,
different thing. When we changed it? Of course
| | 03:48 | it's not the same. It didn't even pass
the other test. And when we created a new object,
| | 03:52 | a new instantiation, it said,
no, those are two different things.
| | 03:55 | They point to different places. So I
hope those Comparison operators are clear.
| | 03:59 | Just to summarise, when we're
comparing objects, two references will always
| | 04:03 | pass both tests, equal equal and the
triple equal, the Identity operator.
| | 04:06 | Instances with matching attributes
will pass the == test. So, yeah.
| | 04:11 | The attributes are the same; they seem
pretty much alike. It doesn't matter if
| | 04:14 | they point to the same data or not.
But they will fail the identity test,
| | 04:18 | because they don't refer to the same
object. And then are of course instances
| | 04:21 | with different attributes will aways
fail both. It will say, "Oh! That's
| | 04:24 | completely different. That's John Smith
and not Jane Doe. I can tell they are
| | 04:29 | not the same right away."
And they failed both tests.
| | 04:31 | So now do we understand how to compare
objects, we understand references,
| | 04:36 | we understand cloning, we understand
constructors, we really have a good
| | 04:40 | understanding of how object oriented
programming works in PHP and we're ready to
| | 04:43 | actually put it into practice and
to start our project they will help us to
| | 04:47 | bring all of this knowledge together.
And that's what we'll start with in the next chapter.
| | Collapse this transcript |
|
|
5. Photo Gallery Project SetupOverview of the project| 00:00 | Now that you have the basics of
working with objects in PHP, the next step is
| | 00:03 | for us to take that and apply it to a
real world project. For that project I
| | 00:07 | have selected a photo gallery for us
to design. What I'm thinking of this
| | 00:11 | website is like Flickr, for example,
where you are able to display a lot of
| | 00:14 | different photos online. People can
view them, they can comment on them,
| | 00:18 | that kind of thing. Of course we're not
going to be as full featured as those kinds
| | 00:21 | of sites, but this would be something
that you could potentially showcase your
| | 00:24 | own photographs to friends and family
and continue to improve it until it did
| | 00:28 | have a lot more features.
| | 00:29 | So, the way I'm thing about this
project is that there will be two parts.
| | 00:33 | There will be a public side and a private side.
The public side will be available to
| | 00:36 | our site visitors. The admin side will
require password for people to get in.
| | 00:40 | The public side will have an overview
of all the images in the gallery and if
| | 00:44 | we have more than, let's say, 10 to
20 images on a page, we want to have
| | 00:48 | pagination, which would mean that we
would have a link that says Next, and that
| | 00:52 | would let us get the next 10 or 20 images.
| | 00:54 | So that's called pagination and we'll
be seeing how to do that. Then of course
| | 00:57 | if you click any of the images,
you would get a full size image view,
| | 01:00 | and we're going to let our site visitors
comment on our photos as well. So there will be
| | 01:04 | a simple web form where they can
post comments about the photographs.
| | 01:08 | In the admin area, of course, we're
going to need to have a login area and that
| | 01:11 | functionally. We saw how to do that in
the essential training. We'll look at
| | 01:14 | that again from an object oriented
perspective, and create admin users, so that
| | 01:18 | we have users who can login to
upload images. That's how we'll get our
| | 01:23 | photographs in there, and of course
delete images and then we'll also want to
| | 01:27 | be able to review and delete comments as well.
| | 01:29 | So that's an overview of sort of the
main functionality that I have in my mind.
| | 01:31 | We might add a few other features as
we're going through, but that will be the
| | 01:34 | core of our photo gallery.
| | 01:35 | Now, let's think about it from object
oriented perspective. What objects are
| | 01:40 | we going to be needing inside of this
project? A good rule of thumb is any
| | 01:44 | database table that you have is going
to have an object associated with it. So,
| | 01:48 | we know we're going to have to have
users, we're going to have to have
| | 01:51 | photographs, and we're going to have
to have comments. So we're going to need
| | 01:54 | three objects, one for each of those,
and creating a new user would then let us
| | 01:58 | ask it for its first name and last name,
for example. Or, for a comment, we can
| | 02:02 | ask for its post time.
That's all object oriented.
| | 02:05 | Now what might not be as obvious to
you are some of the other objects that
| | 02:08 | we're going to be using. One is going
to database, and we're going to have a
| | 02:12 | single object that's going to manage
our connection to the database. Then we'll
| | 02:15 | talk about why that's a good idea. If
you just think about it in abstract terms
| | 02:19 | it sort of make sense that there is an
object out there that's the database.
| | 02:22 | We want to go to the database and get
something. So, think of it that way. It's an
| | 02:25 | object. It's abstract, because it's on
our computer's hard drive, it's a piece
| | 02:29 | of software, but it is an object
that we're putting things in and out of.
| | 02:32 | The same thing is true for session. We
talked about how to use sessions in the
| | 02:35 | essential training where we maintained
the stat of whether we were logged in
| | 02:38 | and out, we'll be doing that with
an object this time. And last of all,
| | 02:41 | we're going to have an object that's going
to manage pagination for us. Now that
| | 02:45 | might not be as obvious as some of
these other ones, but it will be helpful to
| | 02:48 | have an object that can contain all
of the knowledge about whether or not
| | 02:52 | we have more pages, how many pages there are.
We'll put that all into a single object,
| | 02:57 | and by the end you'll
see why that's beneficial.
| | 02:59 | Now we may create some more objects
along the way, but these are the core ones
| | 03:02 | that we're really going to focus on,
and to start with I want us to focus on a
| | 03:05 | making our database connection.
So we're going to start there.
| | Collapse this transcript |
| Creating project and asset directories| 00:00 | Before you start coding on the photo
gallery project, I wanted to do some
| | 00:03 | housekeeping and set up the project
directories for the project. Now that may
| | 00:07 | seem like an incredibly mundane task,
but there are some important points that
| | 00:10 | I want to make while we do it.
So we're going to do it together.
| | 00:13 | So we'll create our new project
directory inside the same place we created the
| | 00:16 | btb_sandbox. For me that's inside my
hard drive, inside users, inside my
| | 00:21 | username folder, inside sites, and
that's where I have got my other folder.
| | 00:25 | You will want to go to the same place
where you put your btb_sandbox folder. So
| | 00:29 | I'll create a New Folder,
and we'll it photo_gallery.
| | 00:35 | While I'm here, I'm also going to
ahead and choose from the File menu to make
| | 00:39 | an alias. If you are in Windows that
would be a short cut and let's go ahead
| | 00:43 | and just drag that onto the desktop
and I'll just change the name of it real
| | 00:48 | quick, and we'll be right over here.
Now it will let me get back to this folder
| | 00:55 | anytime very quickly.
| | 00:56 | So inside the photo gallery folder,
now we need to set up a few other folders
| | 01:00 | as well. If you think about the
essential training, we did the same thing.
| | 01:04 | We created a folder, for images, and a
folder for style sheets and a folder for
| | 01:11 | JavaScripts and we had a folder
for our includes where we put all our
| | 01:15 | functions and everything like that.
| | 01:17 | This time we're going to be creating
two ones as well. We'll have a folder
| | 01:20 | called logs and that's where we
put our log files. Then last and most
| | 01:25 | importantly we're going to have a
folder called public, and this a big
| | 01:28 | difference from what we did in the
essential training, because the images, the
| | 01:31 | JavaScripts and the style sheets
all contain information that should be
| | 01:37 | available to the public.
| | 01:38 | If someone browses to our website,
their browser has to have access to those
| | 01:42 | things. So they are public. So I'm
going to move those into the public folder
| | 01:46 | and that's where we're putting all of
the code which is public, everything that
| | 01:51 | their browser needs access to.
| | 01:53 | So all of our pages will be there.
Even that they are password protected, so
| | 01:56 | that they are part of admin area and
not part of the public area. This is
| | 01:59 | different. This is public, meaning
that a browser you have given the right
| | 02:03 | password and credentials
could get the pages from here.
| | 02:06 | The includes and logs though are going
to be outside the public folder, because
| | 02:10 | the public is not going to
have access to either of those.
| | 02:13 | Now our scripts will still have
access to them. They can go back in the
| | 02:16 | directory and see what's in the
other folders and in fact in our includes
| | 02:20 | folder that's where we put all of our
objects, but all of our pages will reside
| | 02:24 | inside public.
| | 02:26 | I mentioned that, sort of
offhandedly in the essential training. That's a
| | 02:29 | really important security feature.
Now that you know enough, you are in the
| | 02:32 | graduate to doing at this way. So that,
things that public should not hv access
| | 02:35 | to sit back out of outside of that
folder and so we can reference them by using
| | 02:40 | absolute powers and the power system.
| | 02:42 | So now that we have that up end
running, let's just go to TextMate and I'll
| | 02:45 | create a new file and let's just run a
simple a PHP test here. Let's just say
| | 02:50 | echo Is this working and close php tags,
and we'll save it as index.php. And
| | 03:01 | let's just navigate to the photo_gallery.
And then inside public, that's where
| | 03:06 | this is going to go. Save it. I'll close it up.
| | 03:10 | Let's open a Firefox to make sure
that we got PHP working and we can get to
| | 03:14 | that directory okay. So it's going to
be a local host and then if you are on
| | 03:18 | Mac, it's going to have that
tilde and your name, and so it will be
| | 03:23 | photo_gallery, but that's not enough,
we also have to say public. Now when set
| | 03:29 | this up on a public server for the
world actually have access to. What we want
| | 03:34 | to do is wae want to tell u serve up
the contents of the public folder. That
| | 03:38 | will be a starting point. Or if we
were on a shared host or something. Or if
| | 03:42 | you are on a shared host or something,
we can say you know the public_html
| | 03:44 | folder points to this or we make an
alias or a shortcut or a same link or
| | 03:48 | something like that, but you are not
going to want to have your whole path
| | 03:52 | exposed to get to that public folder
if you can help it, because everyone's
| | 03:56 | hosting situation and servers are different.
| | 03:58 | I am not going to go into detail about
how exactly you would set that up, but
| | 04:01 | the point is that you want to point
it to the public directory, but on our
| | 04:05 | development machine, this is still
fine and we know that php is working.
| | 04:09 | Before we move on, we can also
create a couple of other core pages.
| | 04:12 | If you remember in the essential training
we had another file that was called
| | 04:16 | functions. Now just go ahead and save
basic php file inside the includes folder
| | 04:24 | and I'll call it functions.php. So
let's go ahead and drop a couple of
| | 04:29 | functions in here. We can put our
strip_zeros from date functions that
| | 04:33 | we worked on in chapter two.
That might come in handy for us.
| | 04:36 | Another one that I really like, that I
think is really handy, is that redirect
| | 04:40 | to functions that we did in the
essential training. We'll make use of that
| | 04:43 | again here, and then one last one. We
didn't do it as a function, but we did do
| | 04:48 | the code for it, which was
outputting a message. When we were learning
| | 04:51 | messaging, we saw that we would simply
output a message with key tags around it
| | 04:56 | or nothing if there was no message. So
we'll make use of that as well. Let us
| | 05:00 | get started.
| | 05:01 | So those are core functions there and
the last thing that I want us to create
| | 05:04 | is I want us to just go ahead and
start with a basic style sheet, and you can
| | 05:08 | pause the movie if you need to copy
this down. It's a very similar to what
| | 05:11 | we did in the previous training, I have
just got the site colors up at the top and
| | 05:14 | then I have got some basic CSS here.
So this will just give it some basic
| | 05:17 | structure, and I'll just save that in
the public folder inside style sheets and
| | 05:23 | I'm going to call it main.css.
| | 05:25 | Now remember you can pause the movie,
if you need to, to take a look at these.
| | 05:29 | It's just some really simple styles,
very similar to what we did in the
| | 05:32 | essential training. Couple of
differences, I'm using minimum height which, IE 5
| | 05:37 | and 6, don't really like, but
everything after that we'll use it, and that will
| | 05:40 | allow our site to be a little longer
than 600 pixels. I have also added a style
| | 05:45 | here that will allow me to have
bordered tables. So I can give a table class
| | 05:48 | bordered and that will give all the
borders to the table that it needs.
| | 05:52 | So again you can pause the move, if
you want to copy that down or you can use
| | 05:55 | your own styles. This will also be
included in the exercise files for premium
| | 05:58 | subscribers. So I'll save that that and
close that up. So now we have the basic
| | 06:02 | file structures of our website. And
the next step is for us to take a look at
| | 06:06 | setting up the MySQL database.
| | Collapse this transcript |
| Creating a MySQL database| 00:00 | There are a couple of ways that
we can set up the MySQL database.
| | 00:03 | In the previous title, we saw how we could
use phpMyAdmin. If you are comfortable with
| | 00:08 | that and that's all set up, feel free
to go ahead and create a new database here.
| | 00:11 | You can also issue raw SQL commands
through phpMyAdmin, but I'm going to
| | 00:15 | go ahead and do it from the command line,
just so that you can see how that is done as well.
| | 00:19 | So 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:30 | know your root password for MySQL.
Now, if you followed me in the Essential Training,
| | 00:34 | the password we set up was OtlPHP07
and that was the password we had set up.
| | 00:43 | If you have forgotten your
root password you can go to the MySQL
| | 00:46 | website and there are instructions
there for how to reset it and you'll want to
| | 00:50 | follow those. But if this works for you,
and you're inside MySQL with root and password,
| | 00:55 | then now we have the ability to create
new databases, because we're logged in as root.
| | 01:00 | So creating a database is easy. The
caps that I'm typing for create database
| | 01:05 | are not essential; this is considered
good MySQL practice just so that it
| | 01:09 | makes it really clear the difference
between the MySQL commands and then
| | 01:14 | the strings I'm passing.
| | 01:15 | So create database photo_gallery,
that's what I'm going to name it,
| | 01:18 | got a semicolon at the end and that
will create my database. If you are using
| | 01:22 | phpMyAdmin, you will then want to
click on that database to select it,
| | 01:27 | and be able to keep working with it.
If you are here, we have to type USE
| | 01:32 | photo_gallery and that will sort of
switch us in to the photo gallery.
| | 01:36 | It will then know that's the database that
we're working with. We have to type that USE
| | 01:40 | at the beginning, and then I'm going
ahead and just paste in some MySQL--
| | 01:46 | you can pause the movie if you need
to copy it down-- for the user table.
| | 01:50 | Take a look there. I'm going to create
the table users. I'm going to have an
| | 01:53 | id int(11) NOT NULL auto_increment.
We have seen that before. We're going to have
| | 01:58 | a username. It can be 50 characters long.
Password, it can be 40 characters long.
| | 02:03 | First name, 30 characters long. Last name,
30 characters long. And the primary key
| | 02:07 | will be ID. Nothing we haven't seen
before. So now we have our database and
| | 02:11 | we have our first table in there, USERS.
| | 02:13 | That's where we're going to start,
is working with our users table.
| | 02:16 | The one additional step that I want us to
take that we did not do in the Essential Training...
| | 02:20 | In the Essential Training, if
you remember, we just logged in as root
| | 02:23 | all the time. That's a bad practice.
We don't want our web application to be
| | 02:27 | logging in as root. Root really should
be reserved for the times when we want
| | 02:31 | to log in and do these
kinds of special operations.
| | 02:34 | So instead we're going to create a new
user and the way we do that is by typing
| | 02:38 | GRANT ALL PRIVILEGES on and then the
name of database .*. That's the wild card
| | 02:45 | to say everything that is on photo
gallery, grant those privileges to and then
| | 02:50 | inside single quotes, the name of
the user that you want to make it.
| | 02:53 | I am going to make my user called
gallery. You can call it photographer.
| | 02:57 | You 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:05 | So in between those single quotes
localhost and then identified by and
| | 03:10 | I decided that my password for
this user will be phpOTL123.
| | 03:16 | So you can make it something else if
you want, just make sure that you remember it,
| | 03:19 | write it down, but phpOTL123 is
what I'll be using and just by issuing now
| | 03:24 | one command, it creates the user.
So the user_gallery with the password
| | 03:28 | phpOTL123 now has access.
| | 03:31 | So that's all we need to do in MySQL
for now. So I'll go ahead and type quit to
| | 03:35 | get out of that and let's switch back
to our photo gallery and I'll open up
| | 03:40 | TextMate and will start a new file and
if you remember before we had a config file
| | 03:45 | that we put in our includes.
We're going to do that again. config.php
| | 03:50 | and this will hold
our configuration information.
| | 03:53 | So if you remember what we did in the
Essential Training, we set up some constants,
| | 03:56 | some database constants, and
these are the ones that we had set up
| | 04:00 | that I have just simply cut and
pasted in here. We're going to,
| | 04:02 | obviously, want to change those now
for our new user to gallery and to
| | 04:08 | the password phpotl123 and our
database now is just going to be called
| | 04:14 | photo_gallery.
| | 04:15 | There is one additional change that
I want to make here. When defining a constant,
| | 04:20 | a constant can only be defined one time.
We have talked about that before.
| | 04:24 | So it's a good practice to always
keep get in the habit of whenever you are
| | 04:27 | defining a constant to check and see
whether it's already defined or not.
| | 04:31 | It makes it very error resistant.
| | 04:33 | So the way we're going to do that is
by checking to see if it's defined.
| | 04:38 | So we can do if (notdefined(DB_SERVER))
and then we could put our brackets around it
| | 04:49 | and now it's like an if-then statement.
| | 04:51 | So if it is not defined, then define it.
The more common way you will see this written
| | 04:55 | is like this. They are using
that ternary operator. So if it is defined,
| | 04:59 | then return NULL, if it is not defined
then define it, and that's the format
| | 05:04 | that I want us to use here.
| | 05:04 | So I'll go ahead and paste all those in,
there we go. So again, if you need to,
| | 05:09 | take a moment to copy those down,
but make sure you understand most of what
| | 05:13 | we're doing there. We're saying
if it is defined then do nothing;
| | 05:16 | otherwise take a second and define it.
| | 05:18 | So, now we have our database, we have
our user table, and we have set up the
| | 05:22 | constants that we're going to be
using to connect to the database.
| | 05:25 | Now 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 ProjectCreating the MySQL Database class| 00:00 | Now we have our project directories
all setup and we have created our MySQL
| | 00:03 | database, we're ready to start building
the foundations of our object oriented project,
| | 00:07 | the photo_gallery. We're going
to start doing that by taking a look at
| | 00:10 | the MySQL database class. The idea here
is to take everything we learned about
| | 00:14 | connecting to databases from the
Essential Training and apply what we have
| | 00:17 | learned about object
oriented programming to it.
| | 00:19 | Let's start by taking a look at those
steps that we learned in the Essential
| | 00:22 | Training. The very first step is that
we'll require the config file that has
| | 00:27 | those constants defined in it and then
we have five basic steps. We're going to
| | 00:30 | create a database connection, select
the database we want to use, then perform
| | 00:34 | the database query, use the returned
data from that query and then close the
| | 00:38 | connection. Steps 1,2 and 5 will be
the same for our entire project.
| | 00:42 | It's really steps 3 and 4 that will vary
from page to page and we saw that also in
| | 00:47 | the Essential Training. Now let's see
how we can put these into an object.
| | 00:50 | I am going to start by creating a new
file and we're going to save that in our
| | 00:53 | includes directory as database.php.
Let's just open this up a little bigger and
| | 01:00 | we'll just put it over here, so that we
can see both at once. Now we know that
| | 01:05 | we still are going to want this require.
That hasn't changed at all. That will
| | 01:09 | happen even before we define our
class, which will be MySQLDatabase.
| | 01:12 | Now you might be wondering, why I went
ahead and called it MySQLDatabase and
| | 01:19 | not just simply Database. Well, we
could, but my thinking here is that
| | 01:23 | if we had a different class for every
database, then it would be really easy for us
| | 01:27 | to swap out databases. So let's go
ahead and when we're done, we're going to
| | 01:30 | instantiate $database = new
MySQLDatabase;. That's the idea.
| | 01:38 | That's what we're going for here. That way,
database is ready to go, ready for me to use.
| | 01:43 | As soon as this file is done, it will
not only define the class but create a
| | 01:47 | new database and assign it a database.
If I, for example, want to change it
| | 01:52 | someday, I can have another one, that
is, my OracleDatabase, or another one,
| | 01:56 | that is, my MSSQLDatabase, for example.
But for now, we're just going to use
| | 02:01 | MySQL, but we already have that sort
of modularity built in. We can even have
| | 02:05 | something that looks in a config
file to decide which one of my database
| | 02:08 | adapters should I use. So I think this
is just a good programming technique.
| | 02:13 | Now let's start by taking step 1 here
and let's think about how we can put that
| | 02:16 | into our object. I'll just copy it and
we're going to need to put it inside a
| | 02:20 | method. So let's go ahead and say
function, and let's call it simply
| | 02:24 | open_connection. Let's paste all of
that we just had in there. We don't need
| | 02:30 | this 1 anymore. I'll go ahead and move
this over and expand it a little bit, so
| | 02:33 | you can see it a little better. There we go.
| | 02:36 | So now, we should be able to call
$database->open_connection and it would
| | 02:45 | open a connection for us. That is what
we're going for. So this is got to be a
| | 02:48 | public function, we saw that. There is
a couple of more things we need to do
| | 02:52 | though, because just opening the
connection doesn't do much. This sets a local
| | 02:57 | variable, connection equal to the
connection, but then we don't have access to
| | 03:01 | it. So this is where we're
going to need our attributes.
| | 03:04 | So let's say we're going to have an
attribute here. We'll make it private and
| | 03:09 | we'll call it connection. That is where
we'll store our connection. So we know
| | 03:14 | then that we have to change these
to refer to the instance variable,
| | 03:17 | this->connection. So now it will
create the connection for us and then assign
| | 03:23 | it to that attribute.
| | 03:25 | So now, whenever we want to talk about
the connection, we can refer to it as
| | 03:29 | database->connection. Then do
whatever we want with that connection, except
| | 03:34 | that it is private. So we're going to
need another way to access it, the same
| | 03:38 | idea as that bank vault and the bank
teller that we talked about, but we have
| | 03:41 | done a good thing by storing it
because now it is part of the object and that
| | 03:44 | connection is held on to.
| | 03:46 | Now you may be thinking, isn't there
an easier way to do these two steps?
| | 03:49 | We 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:58 | need this step. As soon as we create
the database object, it creates the
| | 04:02 | connection for us. So we can already
start to see how we're going to put all of
| | 04:06 | these database connection parts into our object.
| | 04:10 | Let's fold these up and now let's try
creating another one here for public
| | 04:16 | function close_connection. That
should be obvious enough. We'll just come
| | 04:22 | down here and grab these from step 5.
Of course, we're not looking at just
| | 04:28 | connection anymore, now we're looking
at this->connection, the attribute. So
| | 04:34 | there we are. Now we have brought in
close_connection. So that's all there
| | 04:37 | really is to taking those kinds of
function and putting them into an object.
| | 04:42 | Now we have the ability if we wanted to
say $database->close_connection. Now
| | 04:51 | it will open the connection when it
creates it. Then in the next step, it will
| | 04:54 | close it. It will still be able to
find the connection because it's held in
| | 04:58 | that instance variable.
| | 04:59 | Before we leave this, once we open
the connection, we also know that we're
| | 05:02 | always going to want to the step 2 here.
That is going to happen every time. So
| | 05:06 | let's go ahead and copy that and let's
go ahead and perform that at the same
| | 05:09 | time. We're going to put it in the
else statement. So if there is no
| | 05:13 | connection, then die. But if there is
a connection, then go ahead and select
| | 05:17 | the database, this->connection, write
actually to make that little change.
| | 05:21 | If there is not a database selected,
then die also. But if there is,
| | 05:26 | then just keep going.
| | 05:26 | So now we have both our open and our
close connections. So I'm going to go
| | 05:32 | ahead and take this out. We don't want
to close it. We're going to want to keep
| | 05:34 | it open because now this is available
to us. All we need to do is refer to the
| | 05:39 | object database on any page that has
included this database.php file and
| | 05:44 | we have full access to our database.
You may want to call this just db.
| | 05:48 | That is very common. Or we also saw that
you could do db = &database and that will
| | 05:56 | point it to the reference. You could
also refer to that same MySQL database
| | 05:59 | object by just using db. I'm going to
use database all the time, but I'll go
| | 06:03 | ahead and leave it there,
just so that you have it.
| | 06:06 | In the next movie, we'll continue
building our database class by looking at how
| | 06:09 | we can put in step 3.
| | Collapse this transcript |
| Adding queries to the MySQL Database class| 00:00 | In this movie, I want you to take a
look at how we can get our MySQL database
| | 00:03 | class to actually perform database
queries for us. Specifically, I want to
| | 00:07 | focus on step 3 out of our five
connections on performing database query.
| | 00:11 | The SQL is going to change each and
every time on different pages.
| | 00:14 | We're going to want to run SQL on different
tables, we're going to want to ask for
| | 00:18 | different things, we're going to want
to inserts and deletes, but this part
| | 00:21 | here is the same every time. We're just
simply doing a query, getting the result back
| | 00:26 | and making sure the result exists.
| | 00:28 | So let's take that and put it in our
class. I'll just copy it and paste it over
| | 00:31 | here in our class. I'll go down here
and we'll make public function query.
| | 00:39 | Of course, we're going to pass in ($sql).
Then let's just paste in that same code
| | 00:44 | we were working with. Now we know we're
going to need to ask for the connection
| | 00:48 | as the attribute from MySQLDatabase class.
| | 00:52 | Then the one other change we're going
to need to make here is, of course, if
| | 00:54 | there is not a result, die, but
otherwise, we want to return the result. It
| | 01:00 | doesn't do us any good, if we just run
the query and then nothing happens.
| | 01:03 | We want to be able to return it out of the
object and then we'll be able to catch
| | 01:07 | it into a variable. Then we'll be
able to work with those results.
| | 01:11 | In the Essential Training, we all saw
you had a couple of other helper methods
| | 01:14 | that we were using to help us interact
with databases. confirm_query was one of
| | 01:18 | them. I'm going to go ahead and bring
that over into our class. You will see
| | 01:23 | that it does the same thing that was
being done up here. So we can actually
| | 01:26 | take all of this, now that we have a
new method for it, and reduce it down to
| | 01:30 | just confirm_query. Then
we'll pass it in the ($result).
| | 01:36 | Now this can actually be a private
method because it is not something we need
| | 01:40 | to be able to call from outside the
class. The class just needs to be able to
| | 01:44 | confirm that the query has worked. Now
if you ever came over with a case where
| | 01:46 | you did want to be able to do it,
you could make it into something public.
| | 01:50 | I'm just going to change this also from
$result_set to just $result. I think that's
| | 01:54 | just a little cleaner.
| | 01:55 | Then the other one that we were
working with before was this mysql_prep.
| | 01:59 | If you either didn't do the Essential
Training or if you don't have access to that
| | 02:02 | code again, go ahead and pause your
movie, copy this down but remember what it
| | 02:05 | does is it prepares values for
submission to SQL. It does that by doing some
| | 02:10 | checking to figure out whether or not
magic quotes has been set, whether or not
| | 02:13 | we have access to mysql_real_escape_
string. Then it does some processing on the
| | 02:18 | value that we submit. So it is a good
way to just make sure our values are
| | 02:21 | clean and ready to go to SQL.
| | 02:23 | So I'm going to copy that one as well
and I'll close that up. Let's put that
| | 02:27 | one up here, mysql_prep. Even though
we don't have a place that we're going
| | 02:32 | to use it just yet, we can see right
away that it makes a lot of sense for us
| | 02:35 | to have any code related to mysql be
inside our database class. We're grouping
| | 02:40 | our code, so it is easy to know where
to find it. We don't have to wonder which
| | 02:43 | one of our function falls in it, it is
in our database file, makes it easy to
| | 02:47 | find. Then we can modify this later,
if we need to. I'll go ahead for now and
| | 02:51 | let's make it public.
| | 02:53 | So now we have the majority of the
parts that we were working with in the
| | 02:55 | Essential Training rolled into our
database class. We can simply call query
| | 02:59 | on some SQL and it will take care of
the rest for us. So let's try that out in
| | 03:03 | the next movie and make sure that
our database class is working and
| | 03:06 | troubleshoot any problems that we run into.
| | Collapse this transcript |
| Using the database object| 00:00 | Now that we have a database object
that's able to connections and perform
| | 00:03 | queries, we need to try it out and
make sure that it's all working.
| | 00:07 | So we'll just do that in a really rough way.
Open up index.php and we'll put some code here,
| | 00:12 | so that we can try it out.
| | 00:13 | Now the first thing that we need to do
is we need to load in our database code.
| | 00:17 | Now if you look over here in the
directory structure, you will see the
| | 00:20 | index.php is the file that I'm working
in. That's inside public. I need to back
| | 00:25 | a directory, so that I can then go
inside includes and load up database.php.
| | 00:31 | We'll do that with require_once("../
includes/database.php"). That will load in
| | 00:41 | the database file. So that will
define my class and it will instantiate the
| | 00:46 | database very well for us, so that we
can work with it. We just test that real quick
| | 00:50 | by doing a simple if database is set,
echo "true". If not, echo "false".
| | 00:54 | So that's the only thing that's happening
on this page is that it loads in database.
| | 00:58 | So there's no other way that it can be
set. Let's just try that. I'll go into
| | 01:02 | Firefox and for me, that's going to be
localhost/~kevin/photo_gallery/public.
| | 01:05 | That's where we want to be, index.
php. Now you may not need to put the
| | 01:15 | index.php, if your server is set up
to automatically serve PHP index pages.
| | 01:20 | If you are on Windows, of course, you
won't need to put in the ~kevin at the beginning.
| | 01:24 | Now we can see that result is true.
That's the important part. That it came
| | 01:27 | back and it said, yes, it was set.
Great. So let me just switch back now to
| | 01:33 | index.php. Let's try one of our
other methods. Instead of echo "Is this working?"
| | 01:38 | I'm going to try echo and
then ask our database object that we have
| | 01:42 | created to run its mysql_prep method.
It's going to run it on a string. That's
| | 01:46 | what it does. It works on values.
So it's just a simple string and
| | 01:50 | it's ("its working?<br/>").
| | 01:53 | Now the important part is this
apostrophe. SQL doesn't like apostrophes because
| | 01:58 | it uses apostrophes when it's
constructing its values and that's what we need
| | 02:01 | to escape. So what we're wanting to
see ismthat apostrophe. Does it get
| | 02:05 | escaped? So let's just save that,
switch back to Firefox and sure enough,
| | 02:09 | there's the slash in front of it which
makes it acceptable for SQL. We can now
| | 02:13 | use that. That value has
been rendered safe for us.
| | 02:16 | So those are the most basic tests we
can perform. We made sure that the object
| | 02:20 | was loaded in successfully, no
problems there, instantiated to a variable, so
| | 02:25 | we saw the database is set, and we
were able to call one of the methods on
| | 02:28 | that, so we're able to see that method
works. So we know our basic object is
| | 02:31 | working. If not, go back and double
check. Make sure that all your parenthesis
| | 02:35 | and brackets and everything are all
closed properly. If they weren't errors in
| | 02:39 | there, this is your chance to troubleshoot.
| | 02:40 | But I'm going to keep moving and I'm
going to go ahead and try doing some SQL.
| | 02:44 | I just need to open this a little wider.
I have just got some real basic $sql
| | 02:49 | to insert into my users table the
values, id, username, password, first_name,
| | 02:54 | last_name and the values will be 1. And
then the string for my username, which
| | 02:59 | I'm just going to make 'kskoglund.'
You can make it whatever you like. My
| | 03:02 | password, I have made just 'secretpwd'
and then my first_name and last_name.
| | 03:06 | You can put in yours. Then all I'm
doing is telling the database, run that query.
| | 03:10 | That should perform the insert.
| | 03:12 | Now normally when we do inserts, we do
more error checking to make sure it was
| | 03:15 | inserted and everything. Right now, I'm
just doing a really primitive check to
| | 03:19 | see did it work. One way that we can
test that, without going into php.myadmin,
| | 03:24 | is just to search for that value and
see if it's there. So run another sql
| | 03:29 | statement "SELECT * FROM users WHERE
id=1", tell the database object to run its
| | 03:36 | query method on that sql. It's going
to set that variable, $result_set, equal
| | 03:40 | to the value that's returned. Remember,
we had it return a value back to us.
| | 03:44 | Then it's going to run mysql_fetch_
array on that result_set to get the first
| | 03:48 | user. Then from that user,
return the username. Let's try it.
| | 03:51 | Now I'm just going to run this once
because I want to insert into the database
| | 03:55 | only once. There it is. It worked. Now
if I try it again, you will notice that
| | 04:02 | I get a database query problem,
because it isn't able to insert it into the
| | 04:06 | same id multiple times. So if you ran
into problems there, you will want to go
| | 04:10 | into mysql and remove that entry and
then try again. Or you can simply take
| | 04:15 | these three lines here and comment
them out, so that we only insert in one
| | 04:18 | time. After that, it runs without a
problem. We can make sure that we're
| | 04:22 | getting back users.
| | 04:23 | So if all of that works,
we know that our database is working.
| | 04:26 | While we're looking at this, I want to point
out something to you. We have talked about
| | 04:29 | making our code that was basically
database agnostic, that it didn't care
| | 04:33 | whether or not we had mysql or oracle
or whatever. We can see our code here is
| | 04:37 | actually asking for mysql_fetch_array.
That is definitely mysql thing and
| | 04:42 | if we switch databases later, that's going
to break for us. Even though it's one of
| | 04:45 | the methods we defined, we did the same
thing up here when we said mysql_prep.
| | 04:50 | We said that we were prepared for mysql,
but if we change to oracle database or
| | 04:53 | something later, then that
obviously isn't going to make sense.
| | 04:56 | So let's make improvement to our
object. In addition to these methods here,
| | 04:59 | let's add another one. I'm going to
put it right above the private method and
| | 05:03 | I'm just going to call it public fetch_
array. All I did was take mysql out of
| | 05:07 | it, but that way we could have an
oracle adapter, which would do fetch_array,
| | 05:12 | and it would do it in a different
way. It might have a different way of
| | 05:14 | handling it that makes it agnostic.
Then all it does is return the result of
| | 05:20 | mysql_fetch_array on the result_set.
Now we just say okay, database object go
| | 05:27 | ahead and perform fetch_array on the result_set.
| | 05:30 | For changing mysql_prep, let's just
change this now to instead be escape_value
| | 05:35 | instead. We'll come back over to our
database object and we'll do the same
| | 05:40 | thing. Instead of mysql_prep, it will
just be escape_value. Now escaping the value,
| | 05:45 | you can happen in whatever it needs to
happen for whatever database we're on.
| | 05:49 | There are three other database neutral
methods that I want you to go ahead and
| | 05:53 | input here as well. We aren't using
them yet, but let's go ahead and put them
| | 05:55 | in here so that we're ready.
We have looked at them before. We have got
| | 05:59 | num_rows, which performs mysql_num_
rows and returns how many rows are in a
| | 06:03 | result set. We have got insert_id,
which returns the last inserted id over
| | 06:08 | the current database connection. That's
mysql_insert_id. We have seen that before.
| | 06:13 | mysql_affected_rows, how
many rows were affected by the last thing.
| | 06:17 | Each time we're just dropping mysql off
to front of it. Those are going to make
| | 06:20 | for nice database neutral methods. If
a database adapter needs to be swapped
| | 06:24 | in, so that we're using a different
database, our code doesn't break.
| | 06:28 | We don't have to do a massive rewrite.
We have already taken that into account
| | 06:31 | when we wrote our database object.
So let's go ahead and save that.
| | 06:34 | Let's just make sure that it's all working.
Sure enough, everything is still working fine.
| | 06:38 | In the next movie, we'll take a closer
look at how working with this database
| | 06:42 | as an object is actually an improvement
over the functions that we were using before.
| | Collapse this transcript |
| How OOP is an improvement| 00:00 | Over the course of the last several
movies, we have been able to take all of
| | 00:03 | our database functions that we were
using before and put them into a database
| | 00:06 | class. In this movie, I want to just
take a brief look at how that object
| | 00:10 | oriented programming approach is actually an
improvement over just having those loose functions.
| | 00:14 | Now you've probably noticed some of the
advantages to using an object oriented
| | 00:17 | approach as we're going. For example,
we were able to group all of our code
| | 00:21 | together. So things like mysql_prep,
which became escape_value, those can be
| | 00:26 | grouped with our database. So all of
our code for our database is in one place.
| | 00:30 | We also saw how it makes the code
modular. We would be able to potentially swap
| | 00:35 | in a different database, if we needed
to. We were able to write methods like
| | 00:39 | num_rows, which calls mysql_num_rows,
and therefore allows our code to be
| | 00:44 | database neutral.
| | 00:45 | One thing that we didn't explicitly
talk about though is that improvements made
| | 00:48 | to this object are now available on
every page where the object has been
| | 00:52 | instantiated or where it's being
called. So suddenly, by adding the method
| | 00:57 | num_rows to our object anywhere in our
site that we were calling the database,
| | 01:02 | we now have the ability to call num_
rows. So any improvements or complexity
| | 01:06 | that we add to our object
automatically propagates out to that object every
| | 01:10 | time that it's being used throughout our site.
| | 01:12 | Let's make another kind of improvement
like that now. Let's add a new public
| | 01:16 | attribute which will be called $last_
query. It will allow us to find out what
| | 01:22 | the last query, we tried to run, was.
Now in the past, we have done this using
| | 01:26 | just an echo statement and that
was a really good way to debug.
| | 01:29 | Now we can actually just make it a
part of query. Whenever we run a query,
| | 01:32 | we can just set this->last_query = $sql.
So we'll just set that value each and
| | 01:40 | every time, so we can always just ask
this object, Hey! What was that last
| | 01:43 | query you ran? One other place that we
can put that is in our confirm_query method.
| | 01:47 | So let's come down here to this
private method and let's just alter it
| | 01:50 | slightly. Instead of just dieing with
this simple text in the sql_error, let's
| | 01:56 | have it construct a string out of that
same string, but then also add the last
| | 02:01 | SQL query to it and then die
using that string. So let's save it.
| | 02:05 | In order to try this out and see how
it works, one easy way to do it is first
| | 02:08 | to come back over to our index page
and let's just take out these comments
| | 02:12 | where we got that error before, we'll
save it, we'll go back to Firefox and
| | 02:16 | let's reload the page. Database
query failed, we got the same error but
| | 02:20 | now we also get Last SQL query. We can
actually look at our query and see if
| | 02:25 | we can figure out what was wrong with it.
| | 02:26 | Now this must be something you
only wanted in testing. Once we get to
| | 02:28 | production mode, you might want to
come back over here and actually just
| | 02:31 | comment this out, so that it doesn't
get appended anymore. That proves the
| | 02:35 | point that I was talking about. That
simply by commenting it or uncommenting
| | 02:38 | it, it suddenly changes what happens
throughout our website. It changes the way
| | 02:42 | this object behaves.
| | 02:44 | There is one other function that I
think is right for some improvement.
| | 02:47 | Let's jump up here to this escape_value.
Now value might get escaped on a single
| | 02:52 | web page, five, ten, fifteen different
times. Before pulling in a whole lot of
| | 02:56 | form data, we might be doing a lot of escaping.
| | 02:58 | Every single time that this function
gets called, it's going to check and see
| | 03:02 | are magic quotes set. Does this
function exist? Every single time. It occurs to
| | 03:07 | me that that's wasted processing power
and we're just slowing our site down.
| | 03:11 | Instead, let's take these two lines
and we'll just cut them. We're going to
| | 03:14 | just jump up to the top of the document
here. So I'm just going to paste those
| | 03:18 | two checks that go on right here. I'll
take the comment out. I don't need that
| | 03:22 | anymore. Instead of new_enough_php,
I'm just going to rename it as
| | 03:27 | real_escape_string_exists. There we go.
| | 03:31 | What I want to do is set attributes
equal to these. So each of these are just
| | 03:35 | going to become this->magic_quotes_
active, this->real_escape_string_exists. So
| | 03:40 | now what I need is to have those
attributes and I'll make them private. There
| | 03:43 | is no reason I need to get to them
from outside the class. This one will just
| | 03:47 | be called magic_quotes_active and
this one will also be private and
| | 03:54 | real_escape_string_exists.
| | 03:56 | So stop and think about this for a
second. What this means is that now, down
| | 03:59 | here at the very bottom when I
instantiate the MySQLDatabase class, one time
| | 04:04 | and only one time it runs the construct
method. That will check to see is magic
| | 04:09 | quotes active. It will save that
value here. It does the same thing for
| | 04:13 | real_escape_string.
| | 04:14 | So we don't have to waste the
processing power checking that each and every
| | 04:18 | time. Now we have those attributes
that we can check. So instead, let's just
| | 04:23 | copy this one because we have
changed the name. So now if we check that
| | 04:27 | attribute and it's true, then perform
the same thing. We'll just put this-> in
| | 04:34 | front of magic_quotes_active. Then
here we can also put this-> in front of
| | 04:38 | magic_quotes_active.
| | 04:39 | So now, it does the same escape of the
value that it did before, but it doesn't
| | 04:43 | have to waste the processing power
each and every time. Come back to the
| | 04:46 | original point that I was making,
these changes now propagate out to anywhere
| | 04:51 | that we were using the object. I feel
like we have a pretty good database class
| | 04:54 | now. Some people like to go ahead and
populate this database class with all of
| | 04:59 | their database calls and everything,
but we're not going to do that. Instead
| | 05:02 | what we want to do is create a
separate user class. We're just going to make
| | 05:06 | use of the database class, whenever it
needs to access the database. But it can
| | 05:10 | have a lot of other things that are
unrelated to the database in that class as
| | 05:13 | well. So we'll work on the
user class in the next movie.
| | Collapse this transcript |
| Creating a User class| 00:00 | Now we have a pretty good database
class that will connect the database for us,
| | 00:03 | I want us to write our second object,
which is going to be our user class, and
| | 00:07 | the user class will make use of the
database class to connect to the database,
| | 00:11 | and all the information about finding
users will go in our user class.
| | 00:15 | Now we could put those in the database
class, in fact some developers do,
| | 00:19 | but the database class might start to get
quiet large if we have a lot of different
| | 00:22 | finds going on. Instead since these
belong to the user, they are unique to the user,
| | 00:26 | it makes sense to put them there to
group our code according to the user object.
| | 00:30 | So, I'm just going to open up index.php
here. What we want to do is try to move
| | 00:35 | these three lines of code into a class,
so that all of that finding is handled
| | 00:41 | by the class. And instead what we'll
end up with is something kind of like this.
| | 00:45 | Now I'll just put dot, dot, dot
for now. So basically the found user will
| | 00:50 | ask the class to do something and return
to the found user. In one line, that's it,
| | 00:53 | and then we can start to pull
information like username out of it.
| | 00:57 | So let's create the class and figure out
how we can call it to return that found user.
| | 01:01 | I am going to create a new file in
TextMate and I just go ahead and save that,
| | 01:06 | and I'll name it user.php, singular.
Then I'll put our php tags and class User,
| | 01:14 | singular. That's the way we want
to do objects is with singular name.
| | 01:19 | If we had many of them there would be users,
but the singular version of the class is just one.
| | 01:23 | It's also a good idea at the top
here to go ahead and require the database,
| | 01:27 | because we're going to be needing
the database, so that user can make those calls,
| | 01:31 | and even though back over here
in index, we're still saying load
| | 01:36 | the database. It's okay to do it
with require once a second time, because
| | 01:40 | it will say, "Oh! I've really done
that and it will skip it." But since it's
| | 01:42 | a dependency of the class, it's a good
idea to go ahead & have it here at the top.
| | 01:46 | It's just smart programming.
| | 01:47 | Now inside my class, I'm going to go
ahead to paste two methods, which I think
| | 01:51 | is will look very familiar to you.
The first one is find_all and you will
| | 01:55 | notice that I'm using global to pull in
the database, so I can work with it.
| | 01:58 | We talked about global. It brings in the
database variable from the global scope,
| | 02:03 | so that we can use it. Then I'm going
to ask that database to perform a query
| | 02:07 | for me, and here's my query. Just
simply find all from users. That returns a
| | 02:11 | result set and I simply return the
result set back to whatever call this method.
| | 02:16 | The second is find_by_id. It's
basically the same thing, except that
| | 02:18 | it takes an id. The SQL is slightly
different, and it goes ahead and
| | 02:23 | does the fetch_array on the result set.
We're going to have to do that up here.
| | 02:26 | We're going to have to perform fetch_array
each time we go through and fetch a new array,
| | 02:30 | but if we're only returning one,
there is only one object inside this wrapper,
| | 02:34 | there is no sense in returning
both the object and the wrapper.
| | 02:37 | Go ahead and just take it out of its
wrapper and hand back just the array that
| | 02:41 | we'll work with. So I had
just called it found for now.
| | 02:44 | So I'll save this file. There are two
ways that we can go about this and I want
| | 02:48 | us to see both of them. The first, I
want you to notice that this right here is
| | 02:54 | an instance method. We talked about the
difference between instance methods and
| | 02:57 | static methods or class methods
earlier. This is an instance method,
| | 03:01 | which means in order to call it,
I need to have an instance.
| | 03:04 | So before I can call found user,
I've got to say User = new User,
| | 03:11 | just to have an instance of it, and then
I can ask that instance capital User,
| | 03:16 | find_all. That will then find that user
or if I wanted to find just one,
| | 03:22 | let's do that instead. That's a better example.
Find_by_id(1). So I have instantiated it,
| | 03:27 | and then used that instance to
call this method that returns it.
| | 03:31 | Now a lot of times you will see
programmers do it this way. Now there is
| | 03:35 | nothing that's inherently wrong about
in doing it this way. If you prefer this way
| | 03:39 | or if you are used to doing it
this way or maybe someone else's code is
| | 03:42 | done that way, it's not necessarily
wrong. However, I think that the better way
| | 03:46 | to do this is to use static that we
talked about before and make these into
| | 03:51 | class methods.
| | 03:52 | The class method, the difference
is that the function sticks around,
| | 03:55 | that's static, it sticks around
even when we don't have an instance.
| | 04:00 | So we no longer have to instantiate.
Instead we can use our double dot notation and
| | 04:05 | just ask the class directly,
"Hey class, run your find_by_id method" and
| | 04:10 | it returns the value found_user
and then we can do the username on it.
| | 04:13 | Let's go ahead and try that.
Let's just put in echo hr tag here,
| | 04:18 | just to separate it,
and let's load up Firefox.
| | 04:22 | Let's hit Reload. Oh! Class User not found.
That's because I didn't include it up here.
| | 04:26 | So I'm also going to need to of
course require_once user. That was a
| | 04:32 | silly mistake on my part. Let's just go
back to Firefox and try again and there we are.
| | 04:36 | So if we step through what happened here,
the database class was defined then it was
| | 04:41 | instantiated and assigned to the variable
database. Then we define the user class.
| | 04:46 | When we get down here, we've used the
static method to search the database to
| | 04:52 | find id 1. It return to that and then
we're able to say all right give me
| | 04:57 | your Username out of your row.
| | 04:59 | You can also try our find_all method.
You could take a look here. Just going to do
| | 05:04 | another static call to find_all, return
to the user sets. We'll then need to do
| | 05:10 | a database fetch array on each one and return it
to the value user and then go through each one
| | 05:15 | and list the Username, First Name,
Last Name. You can pause it if you need
| | 05:18 | more time to copy that down, but
I'm going to go ahead and try it out.
| | 05:22 | Switch over the Firefox and there we are.
Username: kskoglund, Name: Kevin
| | 05:27 | Skoglund. So with a very small
amount of code in our class definition,
| | 05:31 | we were actually able to clean up all of
these messy SQL that was going on here
| | 05:36 | and make it something nice and clean.
User find by one. It makes it really clear.
| | 05:40 | It's a good narrative to our code.
| | 05:42 | I'm going to make one more change here.
I'm just going to paste in another
| | 05:46 | function, which is find_by_sql. So
this will just take any SQL we send it and
| | 05:51 | perform that on the database. That's a
useful one to have, because we might not
| | 05:55 | always want to just find a single one
or find all of them; we might want to
| | 05:58 | find a subset. So find_by_sql might
come into use in that case. In fact,
| | 06:03 | on your own what I would like you to do is
rewrite find_all and find_by_id so that they
| | 06:09 | use find_by_sql. Keep in mind that they
are static methods. So you want to make
| | 06:14 | sure that you call it statically.
| | 06:16 | Then in the next movie, we'll look at how
we can improve this class further by using
| | 06:20 | instantiation on the results
that come back from the database.
| | Collapse this transcript |
| Instantiating user objects| 00:00 | We created a user object, but so far
our user object has really just been used
| | 00:04 | as a way to find records in the
database and what we have been returning are
| | 00:09 | arrays just rows of data and not really
working with objects, working with them
| | 00:14 | in an object oriented way. So in
this movie I want to just see how we can
| | 00:17 | further improve our code by doing that.
First let's take a look at the results
| | 00:20 | of the assignment I gave you at the end
of the last movie just to make sure
| | 00:23 | we all are on the same page.
| | 00:24 | We introduced find_by_sql as a static
function and what I want you to do is to
| | 00:28 | modify find_all, so that it also calls
statically find_by_sql and we can just
| | 00:34 | simply return the result of that.
That will return whatever find_by_sql gives us.
| | 00:38 | So effectively it's just the same
except that we're providing the SQL for it,
| | 00:42 | find_by_id is slightly different. We're
going to do the same thing, we're going
| | 00:46 | to call it statically, but again we're
going to use that fetch_array to reach
| | 00:51 | in and return that first row
of data out of the result_set.
| | 00:55 | Now this raised an interesting point
for us. What we're actually returning here
| | 00:59 | when we do fetch_array is an array,
it's not an object it's an associative
| | 01:03 | array that has keys and values that
represent a row in our table. Let's go back
| | 01:08 | and look at index.php and see --
actually let's go at the top here I'm just
| | 01:13 | going to delete a lot of this
code we don't need this anymore.
| | 01:16 | So if you will notice where I'm doing
find_by_id, I'm getting a found_user, but
| | 01:21 | I'm not actually getting a user.
What I'm really getting here is a record
| | 01:26 | that's what coming back
to me is a record or row.
| | 01:29 | So I'm going to just change this to
record to make that clear and what I really
| | 01:32 | want to do is be able to work with this
as an object because we really want to
| | 01:36 | be doing object oriented programming
and the reason why is so that we can
| | 01:39 | perform more complex tasks with an
object than we can with just simply text
| | 01:44 | that's in an array. There can be a
lot of complexity built into objects.
| | 01:47 | Here is a good example of that. Look
down here where we have user first_name
| | 01:51 | and user last_name. It's a very
simple case but it would be great if we can
| | 01:55 | have something that's we just called
user full_name and there was a method in
| | 01:59 | our object that we would simply look
at the first_name and the last_name and
| | 02:03 | put them together for us.
| | 02:05 | That's something that's very common and
we would get some benefit out of being
| | 02:07 | able to just call full_name and have
it take care of the rest and there are
| | 02:11 | certainly more complex cases as well,
we could have it pull together at
| | 02:15 | someone's mailing address and maybe it
checks another database here and another
| | 02:19 | database there while it's
constructing that for us. There can be a lot of
| | 02:22 | complexity behind that. Well in order
to do that what we really get to is the
| | 02:26 | point where we can go from our record
to actually having an object and that
| | 02:31 | object would have an attribute like username.
| | 02:34 | So username would just be an
attribute. So let's go ahead and add that
| | 02:38 | attribute over here to our user model.
So we'll just make public and then
| | 02:43 | username. In fact while we're at it
let's go ahead and put in our password, our
| | 02:47 | first_name and our last_name as well,
so that all of those attributes are
| | 02:51 | there. And let's not forget that there
is one other column in our table, which
| | 02:54 | is the id column. Let's go ahead and
save that as well. Basically every column
| | 02:58 | that's in our MySQL table has an attribute.
| | 03:01 | So what we can do is when we bring
that row out of the database, we'll just
| | 03:05 | take a second and we'll assign all
those values to their correct attribute. So
| | 03:10 | let's save this and let's switch back
over to index and let's do exactly that.
| | 03:15 | We're going to need a user object. So
we can't forget to instantiate a new
| | 03:20 | object but we don't one have yet.
| | 03:21 | So new User, now we have an object and
now we can perform those assignments. So
| | 03:28 | let's do the first one here user_id
is going to be equal to the record and
| | 03:35 | we're looking for it's id in the array
just to save us some time, I'll go ahead
| | 03:40 | and cut and paste the other ones in
there. Remember that you can pause the
| | 03:43 | movie if you need to it to have a
little more time, but this will then give us
| | 03:47 | attributes that we can work with.
| | 03:49 | Let's save this and I'm just going also
comment this out. I can do that in Text
| | 03:53 | Mate with Command and the forward
slash and that will just give me quick
| | 03:57 | comments on those. You can also cut and
paste them out, or type them in by hand
| | 04:01 | and let's just switch back to
Firefox and try it and there it is.
| | 04:04 | Now this is no longer just an array,
it's actually an attribute of an object.
| | 04:10 | Just so we can make very clear why
that's useful, let's switch back over to our
| | 04:14 | model. I'll close these up, so they
are out of our way and I'm just going to
| | 04:18 | add a new method here called full_name.
So you can take a second to copy that
| | 04:23 | down but what's it's doing it's
checking to make sure that first_name and
| | 04:25 | last_name are set and if they
are it returns the two together.
| | 04:29 | So I'll save that, let's come back
over to this page and now instead of
| | 04:34 | username let's ask for full_name and we
have to have this parenthesis to let it
| | 04:39 | know that it's a method name that's the
difference. This would be if it was an
| | 04:41 | attribute this is a method.
Let's go back to Firefox and voila!
| | 04:46 | Now instead of doing something
clumsy like this every time we want to put
| | 04:51 | together the first_name and last_name,
we can do simply this. So this is
| | 04:55 | getting as closer to an object oriented
approach, but just like before when
| | 04:59 | we had all of our raw SQL sitting here
and we turned it into the find_by_id
| | 05:03 | method, we can take all of this and
actually push it up into the object as well.
| | 05:08 | An object should know how to build itself.
| | 05:11 | And we can do that by creating an
instantiate method. So I'm just going to cut
| | 05:15 | all of that out of there and go back
over to my model I'll fold up this method
| | 05:21 | and let's make a new method. This is
going to be a private method. We don't
| | 05:25 | need to be able to access it outside.
We'll just let the class be able to
| | 05:29 | access it and we'll make it static,
function and we'll call it instantiate. And
| | 05:36 | it's going to take as its argument a record.
| | 05:39 | I am going to paste all that old code
in there and of course instead of user
| | 05:45 | now I'm just going to make it object
just so it's a little clearer that that's
| | 05:49 | what we were creating here is an
object. And these are all still fine, I'll
| | 05:54 | just do a quick little cleanup on it
so these rows look nice and clean it's
| | 05:58 | nice. It's nice and organized then
and instead of user I can refer to it as
| | 06:02 | simply self.
| | 06:03 | So create a new version of yourself
and instantiate yourself and in the very
| | 06:08 | end once we have done assigning all
these attributes then we just say return
| | 06:13 | object. That will now
instantiate an object for us.
| | 06:17 | Now in the next movie we'll see how
to make our find methods work with this
| | 06:21 | instantiation, but I want to look at
the couple of improvements we can make
| | 06:23 | here first. The first is that I
just want to know that we could do some
| | 06:26 | checking the record actually exist
and that it is in array before we start
| | 06:29 | doing that. That's not a bad idea.
| | 06:30 | So the second thing is that this is a
simple long form approach. You can see
| | 06:34 | that if we had a table that had let's
say 50 different columns in it then
| | 06:38 | we would have to list all of those out
here and that's a little bit tedious to do.
| | 06:43 | So another way to do it instead
would be something that's a little more
| | 06:47 | processed, a little more computer
savvy. We'll loop through each of the
| | 06:52 | attributes and what we'll do is we'll
just check to see does that object have
| | 06:57 | an attribute? This is has_attribute.
This is something that we're going to have
| | 07:00 | to write. What we're going to do is
true or false, does it have that attribute?
| | 07:04 | And if it does had the attribute then
assign it that value and return that
| | 07:08 | value to it and I think
that's a better approach.
| | 07:10 | So I'm just going to comment out the
short form approach, so that what we were
| | 07:13 | using is the longer form approach
instead. So now what we need to do is write
| | 07:18 | that has_attribute method. So I'm
going to make it a private method and it
| | 07:23 | won't be static, it would be a non-
static method because I'm calling it on an
| | 07:26 | instance, notice that has_attribute
and then it will just be an attribute.
| | 07:35 | So this is going to require us to use
a new PHP function that we haven't seen
| | 07:40 | yet which is get object_vars, I'll
paste in there and then I'll just open this
| | 07:44 | little wider so you can see. I have
got some comments already including get
| | 07:47 | object_vars it says what we're using
and what it does is it looks at this instance
| | 07:52 | that we're working with this and
finds out what are all the attributes.
| | 07:58 | Now one note here is it includes the
private attributes. So just keep that in
| | 08:02 | mind, it includes private one. You can
look at php.net if you want to find some
| | 08:05 | workarounds so that you don't include
the private ones. For our purposes right
| | 08:09 | now it doesn't really make a difference
and then the next thing we'll check is
| | 08:12 | array_key_exist does the key attribute
exist in object_vars in the array that
| | 08:19 | gets return back and that's going
to be the has_attribute function.
| | 08:22 | So this will then instantiate
objects and then it will through all of the
| | 08:26 | columns that are in our table, check
and see if there is a matching attribute
| | 08:30 | and if so, it will assign that value
to the attribute and then we'll have an
| | 08:35 | instantiated object because
it will return the object.
| | 08:38 | In the next movie let's see how we can
modify our find methods to complete this
| | 08:42 | so that they will automatically
instantiate objects when they are finding.
| | Collapse this transcript |
| Revising find methods to instantiate| 00:00 | Now that we have written an instantiate
method in the last movie, in this movie
| | 00:03 | I want to still revise our find method,
so that they perform that instantiation
| | 00:07 | for us. They never return rows.
They always just return objects.
| | 00:12 | Before we do that, I just want to
correct something from the last movie, which
| | 00:14 | is that I inadvertently commented out,
$object = new self. We're going to need
| | 00:18 | that down here. So make sure that the
only thing that's commented out are these
| | 00:21 | assignments. $object = new self still
needs to be in that instantiate method.
| | 00:26 | So I'm going to hide those and I'm
just going to look at find_by_sql to start
| | 00:31 | with, since that's what these other
methods use. What we want to do here,
| | 00:34 | instead of just having a result set and
returning a result set, we want to take
| | 00:39 | that result set and we want to process
it. We want to go through each one of
| | 00:42 | those rows by doing a fetch_array,
pull back a row and then instantiate it.
| | 00:47 | We will assign it to a new array. So
I'm going to create an object_array here,
| | 00:51 | just an empty array. Then I'm going
to do my_sql->fetch_array on the result
| | 00:56 | set, assign it to a row and then
instantiate that row. Now it's going to be a
| | 01:00 | static call to instantiate because
that's a static function. The result will be
| | 01:05 | an object that will just get added to
the object_array. Then at the end, we'll
| | 01:09 | return the object_array. So what we'll
return is an array of objects and our
| | 01:13 | rows and our result set will not ever
get passed back to index, we'll just
| | 01:17 | receive objects.
| | 01:18 | So we'll save that processing. I'm just
going to jump up to find_all and point
| | 01:22 | out that we don't need to make any
changes here. It's already just going to
| | 01:25 | return whatever find_by_sql returns.
So there are no changes there, but
| | 01:29 | find_by_id is going to need to
make a change because it was doing a
| | 01:32 | fetch_array. So there is nothing to
fetch anymore. If it's doing a find_by_sql,
| | 01:36 | that's going to return a result array
to us, not a result set. It's going to be
| | 01:41 | just an array that comes back.
| | 01:43 | So then what we're going to need to
do is still pull that object out of the
| | 01:46 | array. If it's the only one item in
the array, we don't need to return the
| | 01:50 | array, just like before. So instead,
we're going to modify this slightly and
| | 01:54 | I'm going to first make sure that the
array is not empty. If it is empty, we'll
| | 01:58 | return false. But if it's not empty,
then we'll do array_shift($result_array),
| | 02:03 | we remember array_shift from Chapter two,
we're going to pull the first element
| | 02:06 | out of the array. We could also just
return the zero indexed element in the
| | 02:10 | array, but I'm using that
array_shift that we saw earlier.
| | 02:12 | So that's the other change we'll need
to make. Now this will also either be
| | 02:15 | returning an object or returning false.
The reason why we return false is then
| | 02:19 | we have the ability to say if it
returns something, so if we got something back
| | 02:24 | and it will be either true or false.
| | 02:26 | So let's go back over here and let's
just make a modification to index now, so
| | 02:29 | that it can make use of this. This
one no longer be returning a record now.
| | 02:33 | find_by_id will be returning a user
and then we can ask for that user's full
| | 02:38 | name. That's all there is to it. We
have now reduced all of that code down to
| | 02:42 | these two lines.
| | 02:43 | Tell the object to find the item I want
by its id and then tell that object to
| | 02:48 | give me the full name back. All that
complexity reduced down to those two things.
| | 02:52 | Hopefully, you see now why object
oriented programming is really powerful.
| | 02:56 | We can make the same kinds of changes
here to the user set. Instead when we do
| | 03:00 | find_all, it's just going to return a
set of users. So we won't be wanting to
| | 03:04 | do a fetch_array on that anymore.
Now it's just an array that we can loop
| | 03:08 | through. So we don't have to use the
while loop. Instead, we can actually just
| | 03:12 | put in a for each loop. So for each
users as a user, go through and output
| | 03:17 | their user name and their full name.
| | 03:18 | Let's try both of these out. I'm going
to save it. We'll go back to Firefox.
| | 03:22 | Let's hit Reload and there we go. So
notice how much cleaner and more intuitive
| | 03:27 | what's happening in indexes now. It's
a lot easier to see what's going on and
| | 03:31 | all of the complexity is pushed up
into the model, so that it's still
| | 03:34 | accessible but it's out of the way and
grouped with everything else, so we can
| | 03:37 | still find it, if we need it.
| | 03:38 | So now that we know how to instantiate
objects and have it happen behind the
| | 03:41 | scenes, it's going to make it a lot
faster for us to program our pages, pages
| | 03:46 | like index.php, so that we can do
what we want and all the complexity just
| | 03:51 | happens for us automatically.
| | 03:52 | In the next movie, I want to take a
slight detour and talk about the case in
| | 03:55 | which we haven't actually required
the model that we're looking for in a
| | 03:59 | special way that PHP
provides that we can handle that.
| | Collapse this transcript |
| Autoload: The undeclared object safety net| 00:00 | In this movie, I want to make a slight
digression to talk about autoload.
| | 00:04 | I'm calling it the undeclared object
safety net and you will see what that is.
| | 00:08 | You will see that it basically saves
you if you have undeclared objects.
| | 00:11 | Now first let's see what the problem
is and then we'll see how to solve it.
| | 00:14 | Let'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:22 | so that we can use it here. Let's
just try and loading that up without it.
| | 00:25 | I will reload the page, Fatal error:
Class 'user' not found in and it tried to
| | 00:31 | find it inside this file, inside
index.php and it says it was never defined.
| | 00:36 | Now, of course, if you are a good
programmer, you are going to want to always
| | 00:39 | use this require_once, but I want to
show you the safety net that can help get
| | 00:43 | you around it, if that's not the case.
| | 00:45 | Let's open up our functions.php file
and we have got a few functions in here
| | 00:49 | already. I'm just going to fold
those up so they are out of our way.
| | 00:52 | We're going to add a new one and it is
this autoload. It's __autoload. Now that
| | 01:00 | has the same format of the __ as we
did for our constructors and destructors
| | 01:05 | and clone, but it's not inside an object.
It's just a standalone function that
| | 01:09 | exists outside of an object.
| | 01:11 | Now, of course, if we're going to make
use of it, we have got to also make sure
| | 01:14 | that we require our functions in here.
Functions, so that we actually have
| | 01:19 | access to it. So now autoload will have
been defined, when it gets to the point
| | 01:24 | where it says, oh user, that's not the
find, I have an error. It will stop and
| | 01:28 | first check to see is there an autoload
function defined and it will call it
| | 01:34 | and it will ask it basically, hey,
what should I do? It will pass in as an
| | 01:38 | argument, the class name that it's
looking for. In this case, USER. So then
| | 01:43 | we can provide instructions on
what it should do to handle it.
| | 01:47 | So I'm going try just making some
simple instructions here. I'm going to say
| | 01:51 | take the class name, make it all
lowercase, then put php at the end,
| | 01:56 | see if the file exists and if it does,
require it and voila! The problem will be solved.
| | 02:01 | If not, then die with an error that
says the file could not be found.
| | 02:06 | In that case when it's not found, we'll get
something that's prettier than the ugly
| | 02:11 | error output we got before.
| | 02:12 | So let's try it now and see if that
works. We'll switch back over to Firefox,
| | 02:16 | the file user.php could not be found.
Well, that's because we have to tell it
| | 02:19 | where to find it. So in this case,
this function is actually looking from
| | 02:24 | index.php. So I'm going to have to
put a .. includes/ to get into the right
| | 02:31 | directory where that class might be.
So that's going to be my includes
| | 02:34 | directory. That's where everything is.
Let's take a look again to see if that works.
| | 02:38 | Now it works fine. That's why I have
called this path. This is going to be the
| | 02:41 | path that it takes to get there.
We're going to work on this a little bit
| | 02:45 | later, we're going to talk more about
paths and we're going to refine it a
| | 02:48 | little bit, but for now, this will
tell everything that's in that root
| | 02:52 | directory of public, how to find it.
| | 02:54 | Now we're going to run into a problem,
of course, if we're not in the root
| | 02:58 | directory. If we're in a sub-folder or
something like that, we'll have to have
| | 03:01 | another way to navigate to this.
We'll explore that a little later, but for
| | 03:05 | now, I want to emphasize the autoload
function and let you see that having
| | 03:09 | this base function defined,
we'll tell PHP how we can handle it.
| | 03:14 | Instead of user, let's just try making
up another one. Let's say $junk = new
| | 03:23 | Junk, which doesn't exist of course.
Let's go back to Firefox, The file
| | 03:29 | junk.php could not be found. So we
get something nicer than that old error
| | 03:33 | message, but the main point is that
autoload gives you a safety net for cases
| | 03:39 | when it hasn't been defined yet.
| | 03:40 | Now I know you are all going to be
good programmers and you are going to go
| | 03:43 | ahead and define it anyway, but it's
nice to have this here, so that it can
| | 03:47 | actually find and you could have
several directories. Maybe it looks in five or
| | 03:50 | six places to see is it here? Is it
here? Is it here? If not, then finally
| | 03:55 | fail. It can be as complex as we want,
but it lets us have the opportunity to
| | 04:00 | try and sort it out before we just get in there.
| | 04:02 | Now in the next movie, let's take a
look at how we can build a class that will
| | 04:05 | handle our sessions.
| | Collapse this transcript |
| Creating the Session class| 00:00 | Now that we have a database class and
a user class, I want us to move further
| | 00:03 | along toward the goal of being able to log in
to an Admin area by looking at the session class.
| | 00:08 | Now we took a look at sessions before
in the PHP with MySQL Essential Training.
| | 00:13 | I want us to now look at it with an
eye towards making it object oriented.
| | 00:16 | So to start it with I'm just going to go
to TextMate and open up a new window and
| | 00:21 | I'll save this in the includes folder
and we'll just call it session.php and
| | 00:28 | we'll start with our php tags
and it's going to be class Session.
| | 00:32 | That's going to be our session
class that we're going create.
| | 00:35 | Now if you remember back to what we
learned in the Essential Training
| | 00:38 | the session is going to be maintained on
the server as a file. And what we're going
| | 00:43 | to do is actually get the cookie for
the session automatically sent to us by the
| | 00:48 | browser and we'll be able to look up
what file is there and then in that file
| | 00:52 | we can store things and that way we
can actually store that user state.
| | 00:56 | And that's especially useful for things
like whether or not they are logged in,
| | 00:59 | because we can remember, hey, this
person has been logged in already because
| | 01:02 | I already found their id and I
already marked them in my session file.
| | 01:06 | So every request they make, we just
check the session file. We don't have to go
| | 01:10 | back to the database and say look up
this user, see if they exist and see if
| | 01:14 | they are authenticated and if not get
their password and so on. We can just
| | 01:19 | keep them logged in. The analogy that I
used before was like having a nightclub
| | 01:23 | and having a bouncer that keeps people out,
but if you have a handstamp then you come
| | 01:26 | and go as you like.
| | 01:27 | So before we get started I just want
to put a note here at the top, which is
| | 01:32 | that I want you to keep in mind when
you are working with sessions that it's
| | 01:35 | inadvisable to store database objects
in the session. You can store the id for
| | 01:40 | the object so that you can go find it
again, but you don't want to actually
| | 01:42 | store the entire object, and the
reason why we do that is because the objects
| | 01:46 | that are in the session can become
stale. That is that the database can be
| | 01:50 | updated by other users on the system
while the session still has an old version
| | 01:54 | of it saved in that file. There also
can be pretty large objects too and that's
| | 01:58 | another reason why you don't want to put them
in there because there are large amounts of data.
| | 02:01 | It's much better just to store the id
for let's say a users record and then go
| | 02:05 | back to the database to get a fresh
copy whenever we need something from it.
| | 02:09 | So like our database class we're going to
want our session class to exist right away.
| | 02:13 | So I'm going to do the same instantiation
at the bottom of the file that
| | 02:16 | we did for the database class.
| | 02:18 | So when this loads it will define
session and it will create one for us
| | 02:21 | automatically.
| | 02:22 | So that means that a lot of the setup
that we're going to want to have happen
| | 02:25 | is going to take place in our construct
function. If you remember back to what
| | 02:30 | we learned in Essential Training,
the main thing we need to get the sessions
| | 02:34 | rolling in PHP is session_start. If you issue
that PHP command it gets the session started.
| | 02:40 | It figures out the cookie and
it binds the session for us.
| | 02:44 | So that that's all taken care of
and if there wasn't a previous session,
| | 02:47 | then it creates a new one. Other than
including this session file in our index file,
| | 02:51 | this is actually all we need to get
session started. It's that simple.
| | 02:56 | We basically have just said all right,
make a new session object and when you make
| | 02:59 | that object, get the session started
in PHP and now we're ready. We have sessions,
| | 03:03 | they are available to us
and we can start working with them here.
| | 03:06 | But because it's an object now
we're going to want to have attributes,
| | 03:09 | so that we can keep track of things.
| | 03:10 | So for example I'm going to want to
keep track whether someone is logged_in and
| | 03:15 | I'll have a flag for that. Another one
is the user_id. I'm going to want to have
| | 03:19 | a flag for that.
| | 03:20 | Now the user_id is going to be public.
Someone would be able to ask the session for it,
| | 03:23 | but logged_in I'm actually
going to make private. So that only
| | 03:27 | the session can figure out whether
someone has been deemed logged in or not.
| | 03:31 | That's not something that we can
change the value of on our own.
| | 03:34 | So from our application we can't just
say logged_in true, logged_in false. Now,
| | 03:38 | we certainly could do it that way, so that
we just handle it from outside the session,
| | 03:42 | but again we're trying to push
all of the complexity about logging in
| | 03:45 | everything into this session object.
| | 03:47 | So I'm going to create a new function
here called check_login and that'll ask
| | 03:51 | the session, we have already created a
session, to see if the user_id is set.
| | 03:55 | And if it is then it's going to set user
_id equal to that value and it's going
| | 04:00 | to make logged_in = true. If it failed
defined it then it will unset that value
| | 04:04 | and make logged_in = false. In fact we
can go ahead and say logged_in = false
| | 04:09 | at the start.
| | 04:10 | So now when the construction happens,
it would be great if we went ahead and
| | 04:14 | also just ran this method. Check the
login. So start the session and then find out
| | 04:19 | is the person already logged in?
It works a lot like the way we did
| | 04:22 | the instantiation before. We're setting
these attributes based on data that we find.
| | 04:27 | And then even though that's all I'm
really going to do here is just establish
| | 04:30 | the fact that they are logged in or not,
we could have something else here that said
| | 04:34 | if they are logged in then do
a certain set of actions right away.
| | 04:37 | If they are not logged in then do
another set of actions right away.
| | 04:41 | This is not where we're going take care
of redirecting a user to a login page or
| | 04:44 | anything like that. Don't be fooled by that.
We'll take care of that somewhere else.
| | 04:48 | We will do another test for are they
logged in. But this is just a place where
| | 04:51 | we could take additional action and
I just want to highlight that to you.
| | 04:55 | Now that we have a private function for
checking whether they are logged in or not
| | 04:59 | what we're still missing is a public way for us
to find out whether the session succeeded or not.
| | 05:05 | So it gets constructed, it marks all
the attributes correctly, but then we need
| | 05:10 | a public function. I'm calling is_
logged_in, which will check and see is
| | 05:15 | the person logged in or not. This is like
the bank teller being able to go to the bank vault.
| | 05:18 | is_logged_in has access to
this method, but we don't directly.
| | 05:23 | What this keeps us from is being able to
write to this method. We can read from it here,
| | 05:27 | but we can't write to it.
We can't set this value in any way.
| | 05:31 | Only the class session can do that.
| | 05:33 | Now there is two other methods that
we're going to need here and those are
| | 05:35 | going to be in the cases when someone
logs in from a webpage. So they enter
| | 05:39 | their username and password. We want
to go to the database, find the user and
| | 05:43 | make sure the password matches
everything, and if it does then we want to
| | 05:47 | say hey session, mark them as logged in
now. Even though they weren't logged in
| | 05:51 | when you got setup, now you
need to mark them as logged in.
| | 05:55 | So here's the way I'm going to do that.
I'm going to write a public function
| | 05:57 | called login. The database will take
care of finding the user based on the
| | 06:01 | username and password. If we get sent
a user then take that user_id and set
| | 06:06 | that equal to both the session id,
so it will be stored for the future and
| | 06:10 | mark it inside this object, so the
object will also be updated. And then mark
| | 06:14 | logged_in as true, since it was marked
logged_in as false presumably before
| | 06:18 | they got to that page.
| | 06:19 | And that will then effectively log
someone into the page. Conversely we'll want
| | 06:24 | to log them out as well. So we'll need
another function here, public function logout,
| | 06:29 | and it will just unset that session
id so that we don't remember it for
| | 06:34 | the future. It will also unset the user
_id here so that that's no longer in effect
| | 06:39 | and marked logged_in as false again.
| | 06:41 | So here now we have a session object
that handles everything for us.
| | 06:44 | When we fire up the application, it figures
out whether they were previously logged in
| | 06:48 | or not and we have the ability whether
they are logged in currently to log them in
| | 06:52 | and to log them out. All by just
issuing these three simple method commands,
| | 06:56 | logged_in, login and logout, and now
our session class will take care of the rest.
| | 07:03 | Now that we have written our session
class let's look in the next movie at how
| | 07:06 | we can write the actual login and
logout pages to make use of this.
| | Collapse this transcript |
| Logging in using the Session class| 00:00 | Now that we have a session class, let's
use that class in order to login to our
| | 00:03 | application. Through a lot of this I'm
moving very quickly because it's things
| | 00:07 | that we covered in the Essential Training.
Remember you can pause the movie if
| | 00:10 | you want to copy down the HTML code
or anything like that at any point,
| | 00:13 | or you can just use your own.
| | 00:14 | The first thing I want to do is I want
us to go into the public folder and
| | 00:19 | I want to make a new folder inside of
that folder. Actually I didn't put it in there.
| | 00:22 | Let's just drag it in and I'm going
to name this untitled folder admin.
| | 00:29 | So that's going to be where all of my
admin code is going to be put. I'm going
| | 00:32 | to put all in that folder and that
way it's really easy for me to try to
| | 00:36 | restrict access to that folder. Index
will be part of the public folder and
| | 00:40 | that will be the public pages.
admin will be the more private pages.
| | 00:43 | The nice advantage of this is that we
also have the ability to just type into
| | 00:47 | our menu bar the same URL, /admin,
and it will load up the adminindex.php.
| | 00:53 | So let's create an index.php for admin.
I'm actually going to just Option+Drag
| | 00:57 | this one in there, so that I have a
duplicate of it and I'm going to actually
| | 01:00 | duplicate it one more time. I'm just going
to Duplicate and I'm just call this one login.
| | 01:05 | Now I'm going to overwrite what's in
there but that gives me some files really
| | 01:08 | quickly that I can work with. The
index page, the page that we want to get to,
| | 01:12 | is actually going to be a menu page.
So I'm going to take everything that's
| | 01:15 | here now and I'm going to
paste over it with some new code.
| | 01:18 | I'm loading in my functions, I'm
loading in my session, and I actually need to
| | 01:22 | go back one more directory here, dot-dot,
there we go. So it goes back into the main
| | 01:26 | directory then back outside of the
public and then into includes from there.
| | 01:30 | It's going to check and see is the
session logged in or not. We wrote that method.
| | 01:34 | It's a method, it's got parenthesis
after it. If that's not true then
| | 01:39 | redirect to login and redirect
was defined inside functions.
| | 01:43 | So this will make sure that we don't
have access to this if we're not logged in,
| | 01:46 | but if we're logged in then it will
go ahead and give us some HTML.
| | 01:50 | Nothing special here.
It just says Menu on it.
| | 01:52 | Notice here at the bottom for the
copyright, I'm using that date function that
| | 01:56 | we learned back in Chapter 2. We
talked about string for time and we talked
| | 01:59 | about date. I'm using date just to
display the year of the current time.
| | 02:02 | So the copyright will always stay current.
It's a nice trick so that my site doesn't
| | 02:06 | fall out of date. When it goes from
December 31st to January 1st my website
| | 02:10 | will automatically update
to say the following year.
| | 02:13 | So I'll save and I'll close it. That
will be enough to get us going on that page.
| | 02:16 | Now what we really want to focus on
though is this login page. So we have
| | 02:20 | everything we had before. We have to
change our directory structure slightly,
| | 02:23 | so that we look backwards one
more directory and we'll talk about how
| | 02:26 | we can improve that coming up soon.
| | 02:28 | We also need to add a new one here,
which is going to be for our session file.
| | 02:33 | Session and that will load up the
session for us. We're not going to want to do
| | 02:37 | any of these steps we were performing before.
We just want to get everything loaded up.
| | 02:40 | Now it's a good policy that if of
course the person is already logged in,
| | 02:44 | let's go ahead and just forward them onto
that index page, that menu. No reason to
| | 02:47 | waste any time on this page. Then
we're going to want to have our form.
| | 02:51 | Remember to give your form tag a name
attribute so that we can check and see it
| | 02:55 | when it's submitted. That's how it
will have a single page submission.
| | 02:58 | We talked about that previously.
| | 03:01 | We want to clean our data that comes in from
the form. I'm just going to put trim on it.
| | 03:04 | And then we just going to do
this step here, Check the database to see
| | 03:07 | if the username and password exist.
That's going to be a placeholder for now.
| | 03:10 | We are come back to that in a bit.
But for now we're going keep going with
| | 03:13 | the rest of us our form and we're going to
say well, if the user was found then tell
| | 03:19 | session to log them in. So this
has got to come up with found_user,
| | 03:23 | found_user, and there will be some
test performed to see whether or
| | 03:27 | not the user is found.
| | 03:28 | If they are, log them in and once they are
logged in redirect them to that menu page.
| | 03:33 | If not then we're going just
display a message that's says
| | 03:35 | the combination is incorrect, and if
the form hasn't even been submitted,
| | 03:39 | then we're just going to initialize those values.
| | 03:42 | Now you can probably guess what the
form below that is going to look like.
| | 03:45 | I'm just going to paste it all in there
and then come back and look at it.
| | 03:49 | It's just HTML, the header, everything's
pretty much the same, staff login.
| | 03:53 | We're running that output_message, which
is in our function, just to make a nice
| | 03:56 | pretty output of our message. The
login form loading the same form again,
| | 04:00 | login.php. username, the value for it
is going to have htmlentities applied
| | 04:05 | that escapes any values that might be dangerous.
| | 04:08 | We want to make sure we always do
that on user-submitted data and
| | 04:11 | the password and then we'll submit those,
and then same thing. Copyright at the bottom
| | 04:15 | and the last step is if the database
connection is there then we can
| | 04:18 | close it. So that's a simple form
that we're going to be using for that.
| | 04:21 | So now we need to just find out the
answer to this: how do we determine if the
| | 04:25 | username and password exist? Well,
we could certainly do the checking here,
| | 04:29 | but again we're doing object oriented.
We want to put that into our object.
| | 04:32 | We want to ask user can you check for me
and see whether or not this username and
| | 04:37 | password is authenticated. So I'll
say authenticate username and password.
| | 04:44 | So that's the key step here is that
we're going to say hey model, run your
| | 04:48 | static method authenticate using username
and password and give me back a found_user.
| | 04:52 | If we get false back then we know
that they weren't found. But if
| | 04:56 | we do get something back and it comes
back true then, then we're going to login
| | 05:01 | the user or not.
| | 05:02 | So we'll save that. Now we need
to write this authenticate method.
| | 05:05 | So we'll just push this aside and we'll
open back up user again. I'll go ahead and
| | 05:09 | collapse down these functions that we
were working on before and now right
| | 05:13 | before full_name, let's do public
static function authenticate. And of course
| | 05:20 | it's going to be passing in the
username, give it a default value, and
| | 05:26 | password, which we'll
also give a default value.
| | 05:30 | So there is our placeholder for it. Now
what we need to do is make it actually
| | 05:34 | find the values that we want. We haven't
taken care of escaping those values
| | 05:39 | yet for SQL. This is a good place to
do that. So we'll bring in the database
| | 05:45 | from the global scope. We'll make
sure that those values are okay to use.
| | 05:49 | Then once they are okay, the SQL we're
going paste in is going to check in the
| | 05:52 | user table and see if the username
and password, if that combination, exists.
| | 05:57 | Now we're not doing any encrypting on
the password. We talked about that in the
| | 06:00 | Essential Training. I don't want to
complicate it here. So it's just a plain
| | 06:03 | text password. You know how to do
encryption if you need to do it. And limit 1.
| | 06:07 | Now the find that we want to perform
though is just like this find_by_id.
| | 06:12 | If we go up here, I'm actually going to
steal all this code and drop down here and
| | 06:18 | paste it in, but instead of find by
that old SQL, we just want to change it to
| | 06:23 | be our new SQL.
| | 06:24 | So find_by_sql, it will give us a
result. It should be a single person or false.
| | 06:29 | If it's a single person, it will
do the array shift on it. Otherwise,
| | 06:32 | it will return false. So we'll just save
that. Take a look for a second and make sure
| | 06:37 | that you understand what it's
doing. It's basically saying hey,
| | 06:40 | can you find this person?
Authenticate are they in the database.
| | 06:43 | It's not actually doing anything to
the session. We could, we could certainly
| | 06:47 | do that here, but we're not. We're just
saying find out if they are there or not.
| | 06:52 | Then over in login, if there they are,
then we tell the session to mark them logged in.
| | 06:57 | So we're handling it here
on the page. Yes, they are there.
| | 07:00 | Maybe we want to do some additional checking,
maybe we want to say well, let's make sure
| | 07:03 | that the found_user has paid all of
their dues or something. Let's make sure
| | 07:07 | they are up to date. We may want to
examine that object further before
| | 07:11 | we actually log them in.
| | 07:13 | So we'll do index.php to get them all
logged in. Now that we have done all this,
| | 07:18 | let's try it. We may very well have
some bugs in it. So let's open up Firefox.
| | 07:23 | Now instead of just public we
want actually go to admin.index.php.
| | 07:28 | So here is the Photo Gallery. Now I'm
noticing that I'm not getting my CSS.
| | 07:33 | That's one bug. So let's just take a
quick look here. I was asking for style sheets.
| | 07:38 | I have got to go backwards one
directory to get the style sheet for that.
| | 07:41 | Let's see if that comes up now.
There it is. So there is my style sheet.
| | 07:46 | Let's go to Menu and do the same
thing while we're at it, because I know
| | 07:49 | it's going to have the same problem.
| | 07:50 | So that index.php, we're also going to need
to tell it to look backwards one directory
| | 07:55 | to get to the style sheets, okay.
So now we have got that done,
| | 07:59 | let's try logging in. I've got KSkoglund
and secretpwd was my password and now
| | 08:07 | I'm logged in and there it is. It's not
very pretty because the menu has actually
| | 08:10 | got a flaw in the HTML. Let's take
a look that real quick and fix that.
| | 08:15 | It looks like I'm missing a close div tag.
There it is. Close that div tag.
| | 08:20 | Now let's come back over and try and
reload that page and there we are.
| | 08:22 | So now we can go straight to the index
page. We don't have a logout action.
| | 08:26 | We haven't written that. So we would need
to do that if we want to test logging in
| | 08:29 | and logging out. But we did successfully
see that the first time we try to go to this page,
| | 08:33 | it redirected us to the login.
Then we once entered our password,
| | 08:36 | the session object took care of it and
then let us proceed to the menu page.
| | 08:39 | We have now successfully
been able to use it to login.
| | 08:42 | Now you will notice that in these
files I had some problems here with
| | 08:45 | the styles sheets being located in one
place and having to change directories
| | 08:49 | here again. There is a way that we can
do this more efficiently and handle it better
| | 08:54 | and I want to look
it that in the next movie.
| | Collapse this transcript |
| Initializing files and path constants| 00:00 | In this movie I'm going to show you
how it can be beneficial to have an
| | 00:02 | initialized file that takes care of
loading in a lot of other files, and also
| | 00:06 | have to establish the path
constants that will help you out.
| | 00:09 | In the last movie we saw we had to
make some alternations to this require
| | 00:12 | ones to put another ../ in it as soon
as we created this admin directory over here.
| | 00:17 | And we even had problems with
the stylesheets and locating the right
| | 00:20 | stylesheet as well.
| | 00:21 | We have kind of been laboring a little
more than we needed to over finding some
| | 00:26 | of these files and so I want to
try and clean that up a little bit.
| | 00:29 | It also should set out some alarm
bells in your head that we're repeating
| | 00:32 | ourself so many times by requiring
these same files over and over. What it would
| | 00:37 | be better to just have one file that
would initialize everything for us and
| | 00:40 | that's what we're going to do.
| | 00:42 | I am going to create a new file here
and I'll save it in the includes folder
| | 00:46 | and we'll just call it initialize.php.
And I'll put my PHP tags in it to start with.
| | 00:53 | Let's take all of this here at
the top and we'll just copy it. Move it
| | 00:58 | into initialize and hit Paste. Back over
here that means I can reduce all of this down
| | 01:04 | to just initialize. And at the
top of every one of my pages
| | 01:09 | all I have to do is say initialize and once
it does that, it will load up everything
| | 01:13 | that it needs to load up.
| | 01:14 | So already we have made it better and
if we decide that we need to take out one
| | 01:17 | of our classes or add in a new class,
it will certainly instantly become
| | 01:21 | available to all of those pages if they need it.
| | 01:23 | Now you may be thinking well I don't
necessarily need all of those classes
| | 01:26 | every time. So am I losing something
in efficiency by loading them all in?
| | 01:30 | You are losing a little bit, but PHP is
very fast with loading in these classes and
| | 01:34 | everything. That doesn't take very long.
It takes a lot longer to do things
| | 01:37 | like go to the database.
| | 01:39 | So speed is not going to be as much as
of concern for us, as code organization
| | 01:42 | and we can break it up and modularize
it a little more if we find that speed
| | 01:46 | becomes a problem. We still have this
.. here. We can take that out because now
| | 01:50 | this is actually in the same folder right?
| | 01:52 | So we'll go through each one of these
database and user and we actually had one
| | 01:57 | more earlier if you all remember
which was config and so we'll go ahead and
| | 02:01 | load that in at the same time. Database
was loading because it needed it, but I
| | 02:05 | might as well go ahead and
load in the config file here.
| | 02:08 | Now what I want to do is come up with
some definitions for some paths that
| | 02:11 | we can use that will help us to locate
files easily and see how that will help us.
| | 02:16 | I'm going to start out by
defining the core paths.
| | 02:19 | The first thing I'm going to define is
a constant for DS and if it's already
| | 02:22 | defined then I'll make it null. But
otherwise I'm going define it as the
| | 02:26 | Directory_Separator. That's a special
PHP pre-defined constant. If you are on Windows,
| | 02:31 | it will be a backslash. If you are
on Unix, it will be a forward slash.
| | 02:34 | But PHP takes care of figuring out
which one it ought to be when it boots up.
| | 02:38 | So that will make sure that any path
that we write we're able to use DS and it
| | 02:42 | will work regardless of
what file system we're using.
| | 02:45 | The second one I wanted to set up is
Site_Root. Let me just make this a little
| | 02:49 | wider, there we are. So if the Site_
Root hasn't already been defined, then
| | 02:52 | I'm going to define it and I'm going to
define it as being the Directory_Separator
| | 02:56 | and then 'Users'.DS.'Kevin' so on
'Sites' 'photo_gallery'. The path to
| | 03:01 | my application basically. Yours will
be definitely different from mine.
| | 03:04 | So you will want to work that out,
so it's the same as yours.
| | 03:06 | If you are on a Mac or on Unix you can
go into the Command line and you can try
| | 03:11 | and navigate to that place to where
your site is let's say photo_gallery and
| | 03:15 | then it shows up there but you can also
do pwd and that will show you the list.
| | 03:19 | That will work on Unix. You also can
navigate there. You can go into the hard
| | 03:23 | drive into Users into Kevin and
so on till you get to the path.
| | 03:27 | So we're talking about an absolute file
system path that's important, it's the
| | 03:31 | file system not the web server path
but the file system path. This is for PHP
| | 03:37 | to locate the files that it needs. So
now for example I could tell it in order
| | 03:41 | to find those includes files, no matter
where the file is that's asking for it,
| | 03:45 | the way to get there is to go into
the Site_Root and then into includes.
| | 03:50 | In fact I'm going to be referencing those
include file so often, I'm going to go ahead
| | 03:54 | and make a path for that as well.
| | 03:56 | So Lib_Path is going to be path to the
Library, that's what the Lib is from and
| | 04:01 | I'm going to say if the Site_Root and
then the Directory_Separator and includes
| | 04:04 | and that's how we can find that.
And then we can make use of that.
| | 04:07 | Let's say Lib_Path and the Directory_
Separator again and config, function,
| | 04:13 | session, database and user. In fact
I'm going to go ahead and just paste in
| | 04:17 | some comments that I had prepared for
these, that I'm going to load in the
| | 04:21 | config file first and that's to just
get all those configurations setup. Then
| | 04:25 | I'm going to load in the basic functions,
so that everything after that can use
| | 04:28 | them. Then the session, and the database,
those core objects and then any of my
| | 04:32 | database related classes, those will come last.
| | 04:35 | The order is important and if I do need
to change the order I can just do it in
| | 04:39 | this file. Now notice that I can't
defined these in the config file if I want
| | 04:44 | to also be able to use Lib_Path here.
It won't have it defined unless we have
| | 04:48 | done this step up here.
So just take note of that.
| | 04:51 | The second thing I want to point out to
you is that back over here in the login
| | 04:55 | file we can't use it here either
because when this page first loads, it has to
| | 05:00 | know how to get that initialize.php.
Once it's gets there then everything gets
| | 05:04 | defined and it taken care of, but we
don't have those convenience helpers for us
| | 05:09 | at this point.
| | 05:10 | So where does it help us then? Let's go
into database.php. Here we can use that
| | 05:16 | Lib_Path.DS and then I'll make sure
that it can always find the config file,
| | 05:22 | I'll just copy and paste that. And
let's go into functions. We have autoload;
| | 05:27 | we were looking for the function earlier.
Well here is how we could find it.
| | 05:30 | We can go to the Lib_Path and then look
for the class name there. That's helpful.
| | 05:36 | Let's also look in user.php and
require_once database can do the same thing,
| | 05:41 | the Lib_Path and the database.
| | 05:43 | So we now have a common way that we
can always find the library. Once we have
| | 05:47 | run that initialized file, we have
those paths established for us. So that
| | 05:52 | makes the top of the file a lot
cleaner, but what about the stylesheets and
| | 05:55 | everything? For that we're going to
need to establish headers and footers
| | 05:58 | layouts like we did in the Essential
Training and we do that in the next movie.
| | Collapse this transcript |
| Using path content for layout| 00:00 | In this movie, I want to take the path
constants that we created in the last
| | 00:03 | movie and use them to help us with
the layout of our site. Specifically,
| | 00:07 | the headers and footers that will go at
the top of every page. We broke those out
| | 00:10 | in the essential training and
we're going to do that again here.
| | 00:13 | Now, I have already created a folder
called layouts. So you want to create this
| | 00:17 | inside your public folder and I have
put four files in it header, footer,
| | 00:21 | admin_header and admin_footer. Now,
I'm going to show you just the difference
| | 00:25 | between header and admin_header. Let's
open both those up. You see that really
| | 00:30 | the only difference between them is
this dot-dot in front of the stylesheets and
| | 00:34 | we ran into problems with that earlier.
| | 00:35 | So, the admin_header is going to
find the Style Sheets by going back one
| | 00:39 | directory from the admin folder. That's
how it's going to make sure that it finds it.
| | 00:42 | Now, you may be wondering,
why we don't just use Site Root here at
| | 00:46 | the beginning? And that's because it
won't work for us. Site Root is so that
| | 00:49 | PHP can locate the other PHP files that
it needs to put things together for us.
| | 00:54 | This is different. This is the file
that's going to be served up to the web
| | 00:57 | browser and this is the HTML.
| | 01:00 | So, it's going to be the Site Root, so
this is relative to the site. So in this case,
| | 01:05 | if we open up Firefox, we're inside
the admin directory. We need to go
| | 01:10 | back a directory to the public
directory. Now, it doesn't matter where this
| | 01:15 | photo gallery exists as long as the
web server serves it up. We could be in
| | 01:19 | a number of different places. This will
be www.abc.com/photo_gallery or maybe
| | 01:24 | even just abc.com/public. The point is
that it's a relative route in the URL
| | 01:30 | and that's how we're finding it,
not a absolute file path.
| | 01:33 | So make sure you understand the
difference between the URL route that
| | 01:36 | we're working with and the file path that
we're working with. I'm going to make one
| | 01:40 | more change here, I'm just going to say
Admin at the top of this so that's nice
| | 01:44 | and clear that we're working with the
admin area and I'll save both of those
| | 01:48 | and the footers are exactly the same
between the two, there is no difference
| | 01:51 | and I'll just open it up so you can see
it, it's just the bit of HTML that was
| | 01:55 | at the bottom of the file before.
| | 01:57 | I am going to open up index.php which
is the menu file and I'm going to go
| | 02:02 | ahead and start by making this also
be our initialize.php, I want to take
| | 02:08 | advantage of that and then all of this
here is now going to be replaced by the
| | 02:14 | template and all of this here also
will be replaced by a layout template.
| | 02:19 | Now, we could just simply put in some
PHP and do in include, remember include.
| | 02:24 | Include will just include that HTML file,
drop it in right here and then all
| | 02:28 | we have to do here at the end just put
in what we wanted to include to that path,
| | 02:32 | admin_header.php. But since, we're
going to be doing this a lot and
| | 02:38 | that's a cumbersome thing to write each time.
Instead, I'm going to make a helper that
| | 02:42 | will help us to do that.
| | 02:43 | So I'm going to copy it and we'll go
over to functions and we'll put in a
| | 02:48 | helper method here, function and
let's call it include_layout_template and
| | 02:56 | we're going to provide it a template
name with default of nothing and then
| | 03:01 | we'll paste that in, the include statement
that we're working on, and instead of
| | 03:04 | telling it which one it's going to
be just whatever template is sent in.
| | 03:09 | So, now, we can just use this include_
layout_template helper and when we call
| | 03:14 | that function and this is just a root
function it's not part of a class.
| | 03:18 | Then we'll able to output that template
that will just make it nice and easy to
| | 03:21 | write, so let's try that. There we go
include_layout_template, admin_helper.php
| | 03:29 | and we can do the same thing for
the footer, include admin template,
| | 03:34 | admin_footer.php and that will take
care of our header and our footer and
| | 03:39 | we can really focus on what's in the middle now.
| | 03:43 | Now, we could put this into a class of
its own if we had a lot of these kinds
| | 03:47 | of helpers for layouts, we could roll
them into a class for easy access, but
| | 03:52 | right now since there is just one, I'm
going to put it in my functions file and
| | 03:55 | later, I can roll it into a class if
it becomes more complex. So let's save
| | 03:59 | this and let's just try all this out
and make sure that it's all working for
| | 04:02 | us. We're going to Firefox and see
I've got this weird space up here at the
| | 04:06 | top? I'm just going to open up my CSS
real quick. I think this right here on
| | 04:11 | header h1, if I could just put in a
margin of zero on that h1 tag, close that
| | 04:18 | up and reload it there it
goes, now it disappears.
| | 04:20 | So, I'll leave it here to apply these
templates to the other pages that we have
| | 04:24 | been working on. The important part I
want you to see here is that we were able
| | 04:27 | to use Site Root to tell it where to
locate those files. Site_Root inside
| | 04:31 | public, inside layouts, locate the
template and we can make use of Site Root in
| | 04:36 | that way anytime we need PHP to be able
to locate a file and it doesn't matter
| | 04:40 | where it's located, it doesn't matter
that if it's inside the public folder or
| | 04:44 | if it's inside admin, we'll still be
able to locate the layouts folder and
| | 04:48 | these files from wherever we are.
| | Collapse this transcript |
| Late static binding| 00:00 | In this movie, I want us to understand
what late static bindings are. Before
| | 00:04 | I really try and explain what they are,
I think it's best if I first demonstrate
| | 00:08 | what problem they solve.
| | 00:09 | Let's open up our User class that we
created earlier. Notice how our User class
| | 00:13 | has methods that make database
calls like find_all and find_by_id.
| | 00:18 | So far we haven't been working with any
other database tables but we will be soon.
| | 00:21 | For example, we'll have a table
that will store the information about
| | 00:24 | our photographs and our comments and
when we do, we'll most likely want to have
| | 00:28 | similar methods in their classes that
will also find all photographs or find a
| | 00:32 | comment given its id. And you may
even recognize a lot of these common
| | 00:36 | behaviors working with databases from
the Essential Training, where I refer to
| | 00:40 | them as CRUD. That's C-R-U-D, which
stands for Create, Read, Update and Delete
| | 00:45 | and that's pretty much the standard
interactions that we have with our databases.
| | 00:49 | Well, since we have learned about class
inheritance, we know a good programming
| | 00:53 | habits tells us that we should put
all of these common methods in a common class
| | 00:57 | and then inherit those methods
into our subclasses. So find_all will be
| | 01:02 | made generic enough that it can be
reused over and over by different classes.
| | 01:07 | Let's start that process together.
Let's have our User object extend from
| | 01:12 | a new object called DatabaseObject. So,
I'll just come up here to the top of my class
| | 01:16 | and I'll say extends DatabaseObject.
Now we need to create that class,
| | 01:23 | I'll save this for now and I'll open up a
new window in TextMate and let's go ahead
| | 01:28 | and just save that and I'm inside the
right place and I'm just going to call it
| | 01:33 | database_object.php. And if we take a
look at user.php, we can go ahead and see
| | 01:42 | that all of this is actually going to
be the same. We're going to go ahead and
| | 01:44 | require the database. We're going to
need that. The class name now is going to
| | 01:48 | be DatabaseObject, and we'll go
ahead and just close the class for now.
| | 01:53 | So now our User class will inherit
from this empty class. It won't really do
| | 01:57 | much for us but the inheritance does
exist and we could have other classes that
| | 02:01 | inherit from DatabaseObject. So now
DatabaseObject is ready for us to put
| | 02:06 | methods into it that will be
reused by these subclasses.
| | 02:10 | The one last step that we need to
make sure we do is also to go into
| | 02:12 | initialize.php and make sure that we
load that up. So I'm just going to copy
| | 02:17 | this line here and also load up database_
object, so that will get required as well.
| | 02:22 | We can make sure that we have
that as a core object ready to us before
| | 02:26 | we start loading in classes like user.php.
| | 02:30 | So just to prove ourselves that this all works,
let's go ahead and bring up Firefox.
| | 02:33 | I'm here at my photo_gallery/public
page, this index.php, and you can
| | 02:39 | see that it goes ahead and just
brings up that same information before,
| | 02:41 | where it's finding a user in the database and
then displaying the information about that user.
| | 02:46 | We will come back to this page
periodically to check our work. For now,
| | 02:49 | I'm going to hide that and let's just go
back to user and take a look at these
| | 02:53 | methods that we want to move. Well,
we do want to move find_all, find_by_id,
| | 02:58 | find_by_sql but authenticate and
full_name are really unique to user.
| | 03:03 | That's not something that will be reused but
instantiate and has_attribute will be reused.
| | 03:08 | So let's just take full_name and I'm
just going to move it up here to the top
| | 03:13 | and I'll fold it back up again, so
it's out of the way and same thing with
| | 03:17 | authenticate. I'm just going to grab
all of authenticate and move it up here
| | 03:22 | out of the way and I'm going to
go ahead just to make it really clear,
| | 03:27 | I'll put here at the top of these that
these are the Common Database Methods, okay.
| | 03:37 | So now everything that's above this
comment is unique but everything that's
| | 03:42 | below it is not. So let's take a look
inside each of these. find_all,
| | 03:45 | you'll notice that the problem is that it's
looking for users. So we need to also have
| | 03:50 | a way of specifying which table will be
used for each model. We know how to do that.
| | 03:54 | We can just put another variable
here at the top. It's going to need to
| | 03:57 | be static, so that we have access to
it in our static method and we'll just
| | 04:01 | call it table_name and we know
that's going to default to users.
| | 04:08 | So, I'll also while I'm at it go
ahead and say that it is protected.
| | 04:12 | Don't have to do that, but that's a
good access control thing to do and then
| | 04:15 | I'll take this out and now we can ask
for self::$table_name. And we can do that
| | 04:25 | again everywhere where we find users.
Here it is again. Now, I can't use this
| | 04:30 | notation. That won't work with self.
Instead, each time I have to actually
| | 04:34 | break out of the double quotes and
join it in there. So I have just done it
| | 04:39 | again here. So select all FROM and
make sure there is a space here.
| | 04:43 | The space is important. And then after the space,
self::$table_name and then another space after it.
| | 04:50 | Let's check find_by_sql. It does not
make any reference to the table_name and
| | 04:56 | instantiate, it does not make
any reference to the table_name and
| | 04:59 | has_attribute, does not. So now
we have made these reusable.
| | 05:03 | Let's just make sure that it still works.
We just want to make sure we didn't break anything
| | 05:06 | in that process, so I'll save it and
we'll just come back over here to our main
| | 05:11 | Photo Gallery page, load it up and
everything is still load just fine
| | 05:14 | when I reload the page.
| | 05:18 | Now I want you to stop following me
for a second. I'm going to do a bit more
| | 05:21 | but I don't want you to follow on
because what I'm going to demonstrate next
| | 05:24 | will not work and I don't want you to
get tangled up. So just sit back for a second
| | 05:28 | and watch me demonstrate the
rest of this. I'm going to take all of
| | 05:31 | these Common Database Methods, I'm
going to cut them, I'll save that user
| | 05:36 | object, I'll come into my
database_object and I'll paste them in here.
| | 05:41 | So now I'll just fold them back up
again so they are out of the way. Now all
| | 05:47 | those methods are in the database
object and they should be inherited by user.
| | 05:52 | So everything should still work. Those
methods should just come down into user
| | 05:56 | and be available for me to use. Let's
try it out though. I'll go into the Photo
| | 06:00 | Gallery and reload. Oops! It says well
you need the table_name.
| | 06:03 | That was an oversight of my part. I need
to make sure that I still go ahead and say
| | 06:07 | protected static $table_name because
it wants to find that table_name still.
| | 06:15 | Let's come back and try again, oops!
Database query failed. It was trying to do
| | 06:19 | the find_by_id but it came up with bad
SQL and the reason why it came up with
| | 06:23 | bad SQL is because self::$table_name
was nothing and so it tried to just select
| | 06:29 | all from blank. So it created
a problem. We got an SQL error.
| | 06:33 | Now this is a symptom of the problem I'm
trying to show you, but just to keep going.
| | 06:37 | Let's say we went ahead and set the
table_name="users". Now I know that's not
| | 06:41 | reusable but it will allow us
to hopefully avoid that error.
| | 06:44 | Now it should have a table name.
| | 06:45 | So we'll save it, we'll come back and
reload it. Now it comes back and says
| | 06:49 | oh, wait a minute, you don't have the
method full_name. And you may think well,
| | 06:54 | that's because we didn't move full_name,
we didn't promote it and that's the problem.
| | 06:58 | Well, it is, but that's a little
bit deceptive. The real problem is
| | 07:02 | that it's asking for full_name on the
DatabaseObject class, notice that.
| | 07:07 | That class ought to be user. That's what
we're working with. We're working with our
| | 07:11 | inherited child object. We should be
inheriting things from DatabaseObject but
| | 07:16 | we shouldn't actually be working with
DatabaseObject directly. We shouldn't be
| | 07:21 | calling its method;
we should be calling user's methods.
| | 07:24 | So somehow when we asked for it to find
the user and instantiate a user object,
| | 07:29 | instead it returned and instance of
the parent object. If we take a look at
| | 07:33 | instantiate we'll see where this is
happening. It's because we have object, new self.
| | 07:39 | So it's returning an instance of itself.
Now we would expect that would
| | 07:44 | return the user object, but it doesn't.
And we can go ahead, if we were to put
| | 07:48 | in User here, then it would solve the
problem. It's just not reusable at that point.
| | 07:52 | What we really want to be able
to say to make it reusable is, well,
| | 07:55 | whatever class has inherited this,
create a new instance of that. So that's where
| | 08:00 | our problem is and in fact, that's
the problem we're having up here with
| | 08:03 | table_name was then when it was
asking for self::$table_name, it was also
| | 08:08 | looking in the DatabaseObject class
to get its table_name, not in the users class
| | 08:13 | which had a table_name.
| | 08:15 | So the problem in both cases is this
word 'self.' Anytime we use self in a
| | 08:19 | static method, it refers to the actual
object where it resides, not the class
| | 08:24 | inheriting it. To put it in another way,
when PHP loads up the DatabaseObject class,
| | 08:29 | it binds, B-I-N-D-S, it binds
every occurrence of the word self to class.
| | 08:35 | Before the user class has even
been defined. The binding happens early,
| | 08:39 | when it's created, not late when the
object is called or what we can also refer
| | 08:44 | to as at runtime.
| | 08:46 | Now, as the contrast and to make this
point really clear, $this always refers to
| | 08:51 | the current instance. It doesn't have
the same problem that self does. But self
| | 08:55 | we don't have an instance. We're in a
static method, we're in a class method.
| | 08:59 | So self is always going to have this
problem. Now, you won't hear the phrase much,
| | 09:03 | but this could be called Early Static
Bindings and as you can see it presents
| | 09:08 | some headaches that are
really hard for us to work around.
| | 09:10 | Now there are a couple of different
workarounds that we could try. The first is,
| | 09:13 | we could try to simply avoid using
static methods at all. We would just use
| | 09:18 | instance methods instead. We saw that
earlier, how instead of calling a static method
| | 09:22 | we would instead define it as a
regular instance method and then just
| | 09:26 | create a new instance and then call
the instance method on it. This is a very
| | 09:30 | valid approach and one that a lot of
developers to adopt. I think it's a shame
| | 09:34 | though not be able to use
static methods as they were intended.
| | 09:37 | Now the second workaround is to try
and deduce the class name and we saw
| | 09:41 | earlier how we could use get_class
on an instance to figure out its class name.
| | 09:45 | Unfortunately, if we do that in
this case it's still going to return
| | 09:47 | DatabaseObject. Now there are a lot of
different work arounds on the php.net
| | 09:52 | website where developers have jumped
through hoops to be able to figure out
| | 09:56 | what this class name is. I don't
recommend them and I'm not going to show them
| | 10:00 | to you, but there are some there if
you want to try them. And then the third
| | 10:03 | and I think best approach is late
static bindings. So we're finally back to
| | 10:08 | where we started at the beginning
to talk about late static bindings.
| | 10:11 | Late static bindings is a feature of
PHP 5.3. Now as I'm recording this,
| | 10:16 | that's not out yet. It's in alpha, so it's
still being tested but while you're watching it,
| | 10:20 | you may already have installed 5.3,
in which case you will have these features.
| | 10:24 | Instead of get_class
with late static bindings we also have
| | 10:29 | get_called_class, so that we can
find out what class actually called this
| | 10:34 | static method. So that's going to allow
us to figure out what the class name is
| | 10:38 | and create a new instance of that
class. The other thing that we can do is
| | 10:42 | simply say static:: as our scope
resolution operator instead of the self scope
| | 10:49 | resolution operator.
| | 10:50 | So instead of self, everywhere that
we're using that in our static methods
| | 10:53 | we can just use this new keyword, which is
static, and again that's only in 5.3 that
| | 10:58 | we have that available and this is
different than putting static in front of
| | 11:02 | our function name. This is using it
as a scope resolution operator to say
| | 11:07 | I want you to make a late static binding,
a binding that happens at runtime,
| | 11:12 | not back when you were
defined at the very beginning.
| | 11:15 | So just to be clear once you are using
PHP 5, you will be able to move all that
| | 11:19 | code into DatabaseObject and everywhere
you have self, you will simply be able
| | 11:25 | to call static. And if you ever need to
get the class name, you can do that by
| | 11:30 | simply saying class_name = get_called_
class and should return the class name
| | 11:38 | to you. And then we can create a new
instance by simply telling it to create a
| | 11:42 | new instance of the class_name.
| | 11:45 | Now if you don't have PHP 5.3, which is
the case for me, you are going to take
| | 11:51 | all of that code and you are just
going to replace it with a simple comment
| | 11:54 | that says I'm waiting for Late Static
Bindings in PHP 5.3. Now we're all set.
| | 12:05 | We're ready to go with that. I'll go
ahead and put my methods back in here for now.
| | 12:13 | And we have placeholder inheritance
in place so that all of these Common
| | 12:17 | Database Methods can just be moved
over here and we'll know how to do it once
| | 12:21 | we have PHP 5.3.
| | 12:23 | So if you have it and you want to go
ahead and attempt it, go for it. Now,
| | 12:27 | the details may have changed a little
bit after it finally gets released, but
| | 12:30 | at the moment the best place to find out
information about it is going to be at
| | 12:34 | php.net/lsb. So Late Static Bindings.
http://www.php.net/lsb. So you can look up
| | 12:42 | more information there, find out
all the details and if it changes,
| | 12:45 | that's where also some of those
implementations changes will also show up as well.
| | 12:49 | The important thing for us now is
that you understand what the issue is and
| | 12:53 | understand why it won't work without
late static bindings. Now we're ready to
| | 12:58 | move on the next chapter where we
can talk about working with files and
| | 13:01 | directories so that we can
start to upload photographs.
| | Collapse this transcript |
|
|
7. Working with Files and DirectoriesFile system basics| 00:00 | In this chapter, we're going to focus
on working with files and directories in
| | 00:04 | PHP. I want you to just set everything
we have been doing with object oriented
| | 00:07 | programming aside. We're going to be
focusing on the file system for now and
| | 00:11 | we're going to be coming back to the
object oriented later when we talk about
| | 00:14 | uploading files to the file system.
| | 00:16 | But first we have some basics that
we need to take care of and because
| | 00:19 | we're going to be setting all of that object
oriented programming aside, let's close up
| | 00:23 | our photo_gallery and let's go back
to the btb_sandbox where we were working earlier.
| | 00:27 | And let's create ourselves
a new file in there. Let's call it
| | 00:31 | file_basics.php. Make sure you put it
in your btb_sandbox and this will be the file
| | 00:37 | where we can take a look at some
of the basics of working with files.
| | 00:40 | Now, the most important thing of
working with files in the file system in PHP
| | 00:45 | is the magic constant file, __FILE__,
I'll go ahead and put a br tag at the end
| | 00:54 | of this. Let's go ahead and save this
file and let's open up a new browser window.
| | 00:59 | Again, we want to make sure that we
go back to our sandbox and load up
| | 01:03 | file_basics.php, and look what it
gave me. When it echoed back the value of
| | 01:09 | that magic constant file, it gave me
the full path to get to that file. So
| | 01:15 | it illustrates that it knows exactly
where that file is located. The file that
| | 01:18 | we're loading up. So __FILE is
this file that's being loaded.
| | 01:25 | Now, there is another magic constant
that goes along with it which is LINE.
| | 01:31 | Let's load that up, and you will see it
comes back and it says 4. Now that it's
| | 01:34 | become obvious then that line tells you
what line we're looking at. We can see
| | 01:37 | here it's numbered 4. One caveat with
this is be careful once you include files
| | 01:44 | because then the line number may not be
what you expect. If we have other files
| | 01:49 | that we included, if we're calling
functions inside of functions, so just be
| | 01:52 | careful about that with line number and
then be aware that it may not be quite
| | 01:56 | what you expect.
| | 01:57 | Now if you want to get the directory
information about the file that we're working in,
| | 02:01 | we can do that by calling
a function on it, dirname(__FILE__).
| | 02:06 | We'll pass that in and it will be able
to simply parse out the directory name
| | 02:12 | from the file name. I want to also at
the same time show you that there is
| | 02:17 | another version of this, which is only
in PHP 5.3, and that's simply say DIR
| | 02:24 | and that's the same thing as a magic
constant that will return the directory name.
| | 02:28 | Now you will see mine is a different
color because I'm not running 5.3,
| | 02:31 | yet it hasn't been released at the time
that I'm recording it. This does the exact
| | 02:35 | same thing. They are equivalent. So
for now you can use this. In the future,
| | 02:38 | you can use this, but you also can take
advantage of this once you are using 5.3.
| | 02:43 | So let's just bring those up and try
them, you see it didn't work for me. If
| | 02:46 | you are running on 5.3 you probably will
see the same information there a second time.
| | 02:50 | So now that we understand how to
reference the file that we're in, and the
| | 02:54 | directory in we're ready to start
taking a look at a few functions. The first
| | 02:57 | of these is simply file_exists. Does
the file exist? And if it does, return yes
| | 03:03 | or no. I'm just using a simple ternary
operator here to return yes or no. Of
| | 03:07 | course, the file that we're in does
exist. That's not very interesting,
| | 03:12 | but we could also say something more
interesting like the directory name of this file,
| | 03:17 | when added to /basic.html, does that exist?
| | 03:22 | Now, notice we're building up a path
here. We found a directory name and then
| | 03:25 | from there we added basic.html. So
here is the directory name btb_sandbox.
| | 03:30 | It's just a string and to that we'll
put /basic.html. Does that exist?
| | 03:38 | Yes, both of them exist, the file
that we're in and basic.html.
| | 03:42 | Now, the quirky thing about file_
exists is that it also works on just
| | 03:47 | directories. Does the directory exist?
Is the same thing as file exist. So
| | 03:53 | don't be confused because this is file,
but it really mean is this part of the
| | 03:56 | file system does it exist. So if we
try that on the directory name it also
| | 04:01 | returns true. It does exist.
| | 04:03 | Instead, if we want to find out
something actually is a file or not, we need to
| | 04:07 | call a different method which is is_
file. So we can call that both on the
| | 04:11 | basic.html page and on the directory,
and we'll see what we get back, yes and
| | 04:17 | no, and of course, the corollary to
that is being able to ask not just is it a
| | 04:21 | file, but is it a directory, is_dir. So
is this a directory? Well no, it's not.
| | 04:28 | But this should be a directory.
| | 04:29 | So we'll just do both of those and
check sure enough no and yes, so the answers
| | 04:33 | that come back. And just for the sake
of completeness I want to show you that
| | 04:36 | you also can simply reference the
directory that this file is in by calling
| | 04:41 | dot, dot. Remember, how to use dot, dot
when we were navigating the file system
| | 04:45 | from the command line, it works here as
well. So is dot, dot (..) a directory?
| | 04:50 | And it figures out, yes that's what
we're talking about. It is the directory
| | 04:54 | that this file is in. So
that also works as well.
| | 04:57 | Now, these are going to make up the
fundamental building blocks for working
| | 05:01 | with the file system because before we
write a file, for example, we want to
| | 05:04 | check and make sure that the file
doesn't already exist. Well, after we have
| | 05:08 | written a file we want to make sure
that it does exists. We might want to check
| | 05:12 | that the file exist before we try and
read it, or make sure that it is a file
| | 05:15 | and not a directory, before we try and read it.
| | 05:17 | So these are going to be the
toolbox that we're going to be using going
| | 05:20 | forward. So get use to them,
experiment with them a little bit,
| | 05:23 | and 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:00 | In this movie, I want to just start
to understand file permissions, or more
| | 00:03 | specifically who has what permission
to access, read and write our files and
| | 00:10 | directories. Now permissions can be a
very thorny issue and it require a lot of
| | 00:13 | tinkering to get things exactly
right. It's a big enough subject that
| | 00:16 | I actually recommend that you go off
and research it further on your own.
| | 00:19 | But I'll at least give you an introduction
to get you started on the right path.
| | 00:22 | Now one of the reasons why we want to
use file permissions is because of the
| | 00:26 | security that they provide. They give
an extra layer of security that ensures
| | 00:30 | that people on the web cannot access
files and folders that we don't want them
| | 00:34 | to and once we put our website into
production, put it out for the public to
| | 00:38 | use, we want to be constantly vigilant
about exposing our website to hacking.
| | 00:43 | One tip that I'll give you is that it's
always a good idea if you are going to
| | 00:46 | have files be uploaded that you
upload them into their own special separate
| | 00:50 | directory. Separate from the rest of
your code, because then we can make the
| | 00:53 | permissions on that folder looser and
we can say you are allowed to write to
| | 00:57 | this directory, but some of our other
directories can be a little bit tighter
| | 01:01 | in their security. We can say no you
aren't allow to write anything to these
| | 01:05 | directories, and that way we can make
sure that people don't change our files
| | 01:07 | or modify our code.
| | 01:09 | In general, you want to grant as few
permissions as it takes to get the job
| | 01:12 | done. Now that's once we're in
production, once we have launched to the public.
| | 01:16 | For now we're in development, we're
on our own machine and we don't need to
| | 01:18 | worry about hacking. So we can have
our permissions be wide open, but it's
| | 01:24 | still going to be important for us to
understand file permissions to make sure
| | 01:27 | that we're allowed to do the things
that we want to be able to do on our
| | 01:29 | developed machine, that permissions don't get
in our way and that's all we're looking at now.
| | 01:33 | Now, most of the way PHP is going to
handle permission is going to be the way
| | 01:37 | that Unix handles them, so I need to
say a word first about Windows and how
| | 01:41 | Windows File Permissions works. It's a
little bit easier and it's a little bit
| | 01:44 | harder. The reason it's easier because
it's going to simply manage through the
| | 01:47 | Properties/Security tab. So you will go
to the Properties Profile, click on the
| | 01:52 | Security tab and then you can manage
the permissions for that file.
| | 01:55 | If you can't see the Security tab you
may not need to enable that feature first. Now,
| | 01:59 | the default permissions that Windows
has may work in general, it tends to be
| | 02:02 | wide open and so you probably
won't run into any problems.
| | 02:06 | The other reason it's easier because
the Security model for Windows is much
| | 02:10 | simpler. You basically are user who
either has access or doesn't have access.
| | 02:14 | Now, it's a little bit harder though
because different versions of Windows
| | 02:17 | handle it slightly differently, in the
way that the Properties and the Security
| | 02:20 | tab work are little bit different.
| | 02:22 | In this chapter we'll also present a
little bit of a problem for you,
| | 02:25 | if you're a Windows user because many of
the PHP methods that we're going to be talking about
| | 02:28 | are either going to be fully
ignored or partially ignored. So Windows
| | 02:33 | users default permissions may work and
you may not need this chapter at all.
| | 02:36 | But I think it is still useful for you
to understand in case you deploy to
| | 02:40 | a different environment later.
PHP, remember, is not a platform specific.
| | 02:44 | So now let's talk about the way that
MAC OS X, Unix and Linux do there file
| | 02:49 | permissions because they are all done
the same way. Basically, we have three
| | 02:52 | categories of users that could be
coming to our file. We have user, which is us,
| | 02:58 | the person who created the file,
the owner of the file. There is a group,
| | 03:02 | which is a group of users, and we can
assign people to groups and then there is
| | 03:07 | other, which is everybody, the
public at large. So it's not us,
| | 03:11 | it's not someone in one of our
trusted groups, it's just other.
| | 03:15 | And we have three types of actions
that we can do to a file, or even to our folder,
| | 03:20 | and that is to read it, to write
to it or execute it. And in case of
| | 03:24 | folders or directories execute
actually means list the contents of what's in
| | 03:28 | the directory. But since we're mostly
interested in files, we're talking about
| | 03:31 | being able to run executable files.
| | 03:34 | So let's impose that we have an
imaginary file, and we want to grant
| | 03:37 | permissions to user group and other
that look something like this. We want our
| | 03:41 | user to be able to read, write and
execute a file. Group can read and write it,
| | 03:45 | but not execute it and other can read
it but not write it. It's just a real
| | 03:49 | simple example meant to show you how we
can have different permissions for the
| | 03:53 | different categories.
| | 03:54 | You will notice that I have those
abbreviations r, w and x next to read, write
| | 03:57 | and execute. That's because
those are the abbreviations we use
| | 04:02 | when we summarize these listings. So for user,
if we can both read, write and execute,
| | 04:08 | it gets r, w and x, and in group you
will see it gets r and w and then just a
| | 04:12 | minus sign in place of the execute.
Other, the same thing but with only the r
| | 04:16 | and then two dashes. We call this
symbolic notation, and you will see it from
| | 04:21 | the command line inside Unix, Linux
or MAC OS X. Usually they are all run
| | 04:27 | together and they are in that
same order user, group and other.
| | 04:30 | Now, there is another kind of
notation that you need to know about which is
| | 04:33 | called octal notation. Now, in order
to get from octal notation to symbolic
| | 04:37 | notation, you are going to need to do a
conversion, and the key for conversion
| | 04:40 | is what I have got there. r = 4, w = 2,
x = 1 and the - = 0. So then with that
| | 04:48 | key in mind, we can take rwx and
convert it to 7. And rw will just be r+w so
| | 04:57 | that would be 4+2=6 and r by itself would be 4.
| | 05:01 | Now, we have a shorthand for being
able to talk about that whole string of
| | 05:05 | letters up at the top, and that's
called octal notation. So 7, 6, and 4
| | 05:11 | represents the exact same thing as the
symbolic notation rwxrw-r--. So 764 is a
| | 05:18 | lot easier. Once you do a lot of
these file permissions you start to get
| | 05:21 | familiar with them 777 means let
everyone have access. 000 means let no one
| | 05:27 | have access, 666 means let everyone
read and write it but not execute it. So
| | 05:33 | you start to get the idea.
| | 05:34 | So before you move on to actually
demonstrate this from the command line, I
| | 05:38 | want to talk about one more concept,
which is who am I. Now, that sounds very
| | 05:42 | metaphysical, what I actually mean is
who is the web server. We saw from the
| | 05:46 | file permissions that there is an
owner of these file, so we have to know who
| | 05:50 | the owner of the file is and then know
who the web server is to know whether
| | 05:54 | the web server has access or not.
| | 05:56 | Now, often you will find that the
answer to who am I is nobody. That's sound
| | 06:01 | like a Zen answer but in fact that is a
valid user on a lot of Linux systems is
| | 06:06 | nobody. Sometimes though, instead it
will be WWW or Apache, and I'll show a way
| | 06:11 | that it might help you to determine which
one of these your web server is running as.
| | 06:15 | So here I'm at the command line,
and I'm already navigated inside my
| | 06:19 | btb_sandbox folder so that we can
look at the files that are there. Now the
| | 06:24 | first thing I want to show you is that
if we type ls, it will give us a listing
| | 06:27 | of all our files if we type ls - la, it
will give us a listing of all our files
| | 06:33 | with their permission information.
So you will see now in this list these
| | 06:37 | symbolic notation that we were
just talking about. So for example, in
| | 06:41 | parents.php we have read and write
permission but not execute for the owner of
| | 06:46 | the file, and then we have the group
set to be able to read it and everyone can
| | 06:51 | read it as well.
| | 06:53 | Now, we also can find out who the
owner of that file is. That's given right
| | 06:57 | here. That's the first column where it
says kevin. So I'm the owner of the file
| | 07:01 | here is well obviously say something
different. And the group information is
| | 07:04 | the second column there, what group owns
this file, what group has access to it.
| | 07:09 | Now, we're not going to be talking a
lot about groups but the concept is very
| | 07:12 | simple. If we were to take users and
put them into a group we could then assign
| | 07:16 | ownership of a file to a group and
then everyone who is in that group would
| | 07:21 | have those access permissions. For now
we're just going to be working with user
| | 07:24 | and focusing on the user having access.
| | 07:27 | So we asked who am I earlier. My web
server is most certainly not kevin. Now it
| | 07:32 | might be the part of the staff group
but I don't think it is. So the question
| | 07:35 | is what access then does my web server
have to parent.php. It's not the user,
| | 07:40 | it's not the group, so it would be
other. So in this case it would have read
| | 07:44 | access. If we wanted to modify those
permissions, which we'll see how to do in
| | 07:47 | a bit, then we need to change it for
others so that other would have different
| | 07:51 | permissions.
| | 07:52 | Now, I told you that I'll also give you
a trick that might help you to identify
| | 07:56 | which user Apache is running as. If we
run the command ps aux, that will give
| | 08:01 | us information about the processes that
are currently running. If we then put a
| | 08:04 | space and the upright pipe, so that's
just straight up and down bar, space grep
| | 08:11 | and then httpd. That will look for the
web server process it's running. It will
| | 08:18 | usually be called httpd and if we do
that it will search for lines that contain
| | 08:23 | that, and you will see that we got a
couple back, this is the important one
| | 08:26 | here, which is that I have my web
server running as WWW. You can ignore the
| | 08:32 | underscore that's in front of it.
What's important is that WWW that is the user
| | 08:36 | that my web server is running as.
| | 08:38 | So now that we have understand the
fundamentals of users and permissions,
| | 08:42 | in the next movie let's look at how we
can actually change the users and the
| | 08:45 | permissions on a file.
| | Collapse this transcript |
| Setting file permissions| 00:00 | Now that we understand the
fundamentals of file permissions, let's talk about
| | 00:04 | how to change those file permissions
from the command line. And we're going to
| | 00:08 | be making use of two Unix commands:
chown and chmod. So those are the ones
| | 00:13 | we're going to be using to change the
ownership and to change the permissions.
| | 00:16 | Let's see how that works.
| | 00:18 | So here I'm at the command line where
we left off before. I'm still inside the
| | 00:21 | btb_sandbox. I'm also just going to
real quick go into the sandbox and create a
| | 00:25 | new file that we can use to work
with here and not mess up our other files.
| | 00:29 | So I'll open up TextMate and open a
new file and I'll just say 'This is a file
| | 00:35 | for testing file permissions.' And then
I'll save it in that btb_sandbox folder
| | 00:42 | and we'll call it file_permissions.php,
and it didn't actually have any PHP in it
| | 00:50 | but just to keep at the same as the
other files, we'll give it that extension.
| | 00:53 | So here is file_permissions.php, we see
it right there. Let's do our ls - la trick
| | 00:59 | again to do a list and then we'll now
see file_permissions.php shows up here
| | 01:03 | and we can see it has the same
permissions. Read and write for the owner,
| | 01:07 | which is me Kevin, and for both the
group and other it has the ability to
| | 01:12 | read the file, which allows our web
server to read it, which allows it then to
| | 01:16 | serve up what's in the file.
| | 01:17 | Now just to be clear when we talk about
executing a file, that's not executing it
| | 01:22 | on the web server. All the web server
has to do is just to be able to read-in the script
| | 01:25 | and it will do whatever is in
the script. When we're talk about executing,
| | 01:28 | we're talking about having more of a .EXE
file or something that we can actually run
| | 01:33 | from the command line. Execute is not
going to play a big part when we're
| | 01:36 | working with a web server. Either we
can read or write the file, or we can't.
| | 01:39 | You will remember from the last
movie I was able to find out that my
| | 01:43 | Apache was running as WWW, and that may
be true for you. It also may be Nobody
| | 01:48 | or Apache or something else. I'm
going to go ahead and just show you how to
| | 01:52 | change file permissions to have a
different owner. And I'm going to do that
| | 01:55 | with that chown command, but before
I do that I'm going to type in sudo.
| | 01:58 | Now, you may have use sudo a few times
in the past and not really known what it did.
| | 02:02 | It basically says do this command
with the highest level permissions that
| | 02:07 | the system has. So if I'm allowed to
be a sudo person, if I'm allowed to have
| | 02:11 | that superuser ability, that's what the
su stands for superuser, then I'll have
| | 02:16 | those superuser permissions.
| | 02:18 | So with top level permissions,
try to change the owner to www for
| | 02:26 | file_permissions.php. And it came back.
It didn't give me any response.
| | 02:33 | It just did it. If I type ls - la though,
we'll now see that it is changed the owner to
| | 02:39 | www. So now the ownership has changed,
www has read and write permissions.
| | 02:45 | Kevin just has read permissions. So we
have changed who is the user for this file.
| | 02:52 | Now we can do the same thing to change
permissions. We can say sudo and then
| | 02:57 | chmod and then we're going to pass in
the permissions that we want. And there
| | 03:01 | are number of different ways we can do
that. We can use the symbolic notation
| | 03:04 | that we saw before, that r, w and x,
but I'm going to do with the octal
| | 03:08 | notation that we have talked about.
| | 03:09 | I am going to go ahead and for now
just say 777, so you will see what it does
| | 03:13 | with file_permissions.php. All right,
now let's do ls - la and see that again.
| | 03:21 | And notice now that 777 opened it wide
up so that everybody can read, write and
| | 03:26 | execute. It doesn't matter who the
owner is. Everybody has the ability to
| | 03:31 | access this file.
| | 03:32 | Now, we can have something that's a
little more locked down than that.
| | 03:35 | I'll just simply change this to be 7,
let's say 44. Actually it's 644 is what we had
| | 03:41 | before. I'll go back to that first.
644 and you will see that now it's back to
| | 03:46 | what it was. This is 6, this is 4 and
this is 4. So now I have set it back to
| | 03:51 | what it was.
| | 03:53 | Let's try changing it so that Kevin
doesn't have access anymore. So let's just
| | 03:56 | say 600. Kevin might be part of staff.
So let's go ahead and make sure that
| | 04:01 | staff also doesn't have access. So it'll
be 600. The www user will still have those
| | 04:07 | read and write privileges. And now
let's just try opening that file up.
| | 04:11 | So I'll come back here into my file system.
I'll double-click on file_permissions.
| | 04:15 | You see it comes up blank and I'll type hello
and hit Save. It says oh, it wants your password.
| | 04:21 | So it won't let me do it
because I don't have enough permissions
| | 04:25 | and it doesn't allow me to see what's
in there. So the important point that
| | 04:27 | you need to take away from this
is that in order for your PHP to work
| | 04:31 | successfully, you need to make
sure that the file is readable.
| | 04:34 | Then the web server can read it in
and do whatever it ask it to do.
| | 04:38 | However, now that we're about to
start doing uploading of files, we're also
| | 04:41 | going to need to have directories that
are writable, so that we can actually
| | 04:46 | write to them. And when we start doing
things like log files, we're going to
| | 04:49 | need them to be both readable and writable.
So that we can add entries to a log file
| | 04:54 | and read back what's there as well.
| | 04:56 | Now in addition to being able to issue
command line instructions like chown and
| | 05:00 | chmod, we can do the same thing from
inside PHP and that's what we'll look at
| | 05:05 | in the next movie.
| | Collapse this transcript |
| PHP permissions| 00:00 | Now that we've seen how to manipulate
file permissions from the command line,
| | 00:03 | I want to just see how we can do that in
PHP. Before we can get started on that,
| | 00:07 | we first need to talk about
something in PHP called safe mode.
| | 00:10 | At the beginning of this title,
| | 00:12 | we created a my_phpinfo file that just
simply brings up the PHP info script,
| | 00:18 | and we can bring that up in a browser
and take a look. So here we are at the
| | 00:22 | main page for PHP info. If you do a
search for safe_mode, you'll see that it
| | 00:27 | comes up and gives us safe_mode for me is off.
| | 00:30 | Now yours may say on. It's not so
important whether it's on or off. It's that
| | 00:34 | you know how to change it and what
it does. The way that you change it is
| | 00:37 | you go into your php.ini file and you turn
it on or off. Then you just restart your
| | 00:42 | web server, so that it reloads those
new changes for PHP. That's how you turn
| | 00:46 | it on and off. What safe mode does is
that when safe mode is on, PHP checks to
| | 00:51 | see if the owner of the current PHP
script that's running matches the owner of
| | 00:57 | the file that you want to manipulate.
| | 00:59 | So if safe mode is on, we don't have
the ability to manipulate files that
| | 01:03 | we don't own. Now this is a feature
that was added mostly for shared hosting
| | 01:07 | environments. It's eventually going
to go away in PHP. It's not strictly
| | 01:11 | necessarily for you to have it on,
certainly in your development environment
| | 01:15 | and even in your production environment.
But if you're going to be manipulating
| | 01:18 | file that you don't own, you
will need safe mode to be off.
| | 01:22 | Now that we know about safe mode,
let's create a file where we can start
| | 01:25 | working with our PHP, so I'll open up
TextMate and I'll make a new file and I'm
| | 01:29 | going to save it in my btb_sandbox and
I'm going to call it file_changer.php.
| | 01:36 | Now that may sound like an odd name,
but what I'm after here is that this file
| | 01:40 | is going to be where we manipulate
another file and the other file we're going
| | 01:44 | to manipulate is going to be file_
permissions, the one we're working with from
| | 01:47 | the last movie.
| | 01:48 | So file_changer will be the currently
running script, file_permissions will be
| | 01:53 | the one that we're going to manipulate.
Let's take a look from the Terminal.
| | 01:58 | Remember, I said you could do ls - la,
I'm also going to use that upright pipe
| | 02:03 | followed by grep and then file_. This
will come back and just give me the lines
| | 02:10 | that are related to file_ in the name.
| | 02:12 | So we can see the basics file, we're
not interested in that one. But we can see
| | 02:15 | changer, and we can see permissions.
Now for me, changer is owned by Kevin. WWW
| | 02:23 | though owns file permissions because
we changed it to be that. You may have
| | 02:26 | changed it back or it may be something else.
| | 02:29 | So if we have safe mode on, file
changer will not be able to make any changes
| | 02:33 | to file permissions, because they have
different owners. It doesn't matter what
| | 02:36 | permissions are set over here, even
if we're allowed to execute things, PHP
| | 02:40 | will intervene and say sorry, I'm not
going to let you do that. Instead, I
| | 02:45 | think it's better to have safe mode off,
and then we can control which things
| | 02:49 | we allow PHP to do by
using the file permissions.
| | 02:53 | So to share with us, take a look at the
fileowner function. So, fileowner, and
| | 02:58 | this will tell us the owner of a file.
We're going to say file_permissions.php.
| | 03:03 | That's the file that we want to look
at. Now notice here, I just provided
| | 03:07 | simply a string with the file name.
It's going to assume it's in the same
| | 03:10 | directory. If it was somewhere else I
could say ../ to get it to go back a
| | 03:14 | directory or I could use an absolute path,
we saw how to do that with file+ and so on.
| | 03:20 | But it's going to just assume it's in
the same directory. So let's bring this
| | 03:23 | up in a browser and see what we get, if
we ask for just the fileowner. So here
| | 03:26 | we're with file_permissions and I now
want to run file_changer. It came back
| | 03:31 | with 70, now that's not particularly
useful, it didn't give me www, instead,
| | 03:35 | what it gave me was the ID of the user,
because that's what is stored there and
| | 03:40 | that's what's easiest for it to find.
| | 03:41 | Now we can compare IDs between this
file and a different file, but in order to
| | 03:46 | find out the name, it's a little bit
trickier. And what we're going to need to
| | 03:49 | do is make use of a library that is
probably not installed on Windows and even
| | 03:54 | may not be installed on a Linux, Unix
of Mac machine. It's called the Posix library.
| | 03:58 | So if we have Posix installed, then,
we can do it a little bit differently.
| | 04:06 | Instead, we can say that the owner_id
is equal to this and then we'll pull back
| | 04:15 | an owner_array by saying posix_
getpwuid. Then I'll get the user ID from the
| | 04:26 | password file for the owner_
id. So it looks it up for us.
| | 04:33 | Then once we get that array of
information back about the owner,
| | 04:37 | then we'll pull out the part that we want, owner_
array, just the name, and you can take a look
| | 04:43 | at the full array if you want
to see what else it gives you.
| | 04:45 | So let's try that now.
| | 04:46 | We'll go back to Firefox. We'll reload
it and you'll see we get the www. I'll
| | 04:50 | go ahead and just put in echo br, just
so that we have nice break there. Now
| | 04:56 | that we have the owner name, we
might want to now change the owner.
| | 04:59 | For example, from www to Kevin or to your name.
| | 05:04 | So we saw that out before with chown,
we still have chown available to us in
| | 05:08 | PHP, but it's going to be so
Problematic. It's basically unusable.
| | 05:11 | I'll show you why. We first need to provide
the file name that we want to change the
| | 05:15 | ownership of, and then we need to
provide the new owner name. So for me
| | 05:18 | I'm going to put in Kevin, you can put in
your name, whatever you had before or a
| | 05:21 | different user. Nobody is also
probably a user you could use.
| | 05:24 | So I'll save it. Now before I try this
in a web browser, let's go ahead then
| | 05:29 | and do the same echo statement back
again just so we can see who the owner is
| | 05:34 | after we've done the chown statement.
| | 05:36 | Now, keep in mind before I run this,
that safe mode is off for me. So that's
| | 05:41 | not stopping us from making this change.
You'll remember if we look back at the
| | 05:46 | Terminal that this file is set
to both read and write for anyone.
| | 05:50 | So read and write is not the issue,
it's not a permissions problem. So let's
| | 05:54 | now switch back over to Firefox and
let's try it out. file_changer.php, and it
| | 05:59 | comes up and its says Warning,
operation not permitted. Now, the reason why
| | 06:04 | it's not permitted, you can see in the
documentation for chown on the php.net website.
| | 06:09 | It attempts to change the owner of the
file, but only the superuser may change
| | 06:14 | the owner of a file. That's a pretty
big restriction. You remember when we did
| | 06:17 | chown from the command line, we typed
in sudo. That made us temporarily the
| | 06:21 | superuser so that we had superuser privileges.
| | 06:24 | Well, PHP insist that we always have
to be the superuser if we're going to
| | 06:29 | change the owner of the file. That
means that our web server has to be a
| | 06:33 | superuser. Now that creates a pretty
big security issue for us. If we let our
| | 06:37 | web server have those top-
level access privileges.
| | 06:41 | So for that reason, I don't
recommend it, and it think that makes chown
| | 06:44 | virtually unusable in PHP. So it does
exist, you do have the ability to use it,
| | 06:49 | but I don't recommend it. Instead,
we're going to want to stick with chmod and
| | 06:53 | changing the privileges so that the
privileges allow the right person to access
| | 06:58 | the right file.
| | 07:00 | So let's switch back to our file_
changer and I'm just going to make a note here
| | 07:04 | that says, "chown only works if PHP
is superuser, making webserver/PHP a
| | 07:19 | superuser is a big security issue. But
unlike chown, we can use chmod. So let's
| | 07:27 | see how we can do that. First,
let's see what the permissions are.
| | 07:31 | So we'll say echo, fileperms for file
permissions and then we're going to use
| | 07:37 | the same file, I'll just copy and paste.
Fileperms and let's see what it gives
| | 07:45 | us 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:54 | of that code that we're using to
change to octals and this is not a symbolic
| | 07:58 | notation, but this is a decimal representation.
| | 08:02 | So in order to make it usable, we need
to use a simple function called decoct,
| | 08:09 | which is basically to convert from a
decimal to an octal. So this is one of the
| | 08:13 | only times you're going to use it,
decoct and surround it. Then we'll come back
| | 08:18 | and we'll say all right Firefox, now
give it to me, and it comes back and says
| | 08:22 | 100666.
| | 08:24 | Now the important part is these last
four numbers. The last 3 is what we're
| | 08:28 | used to seeing as an octal. That fourth
one is also going to be something that
| | 08:31 | PHP is going to want us to use. In
fact, if you really want to get just the
| | 08:36 | important part, you can use substring
function wrapped around there, 2, and
| | 08:42 | then when we go back to Firefox, it
will return just those four characters of
| | 08:46 | the file permissions.
| | 08:47 | Now that we have that, let's try and
use chmod to change it. So we're going to
| | 08:51 | change it on file_permissions.php and
let's go ahead and say that the file
| | 08:57 | permissions ought to be 777. Now there
is one big change that we need here.
| | 09:02 | We need to put that 0 in front of it. So
PHP is always going to want to have that
| | 09:08 | 0 in the first place.
| | 09:10 | So, 0, and then the octal number that
we're used to using. So let's try that
| | 09:14 | and then after it's done, let's
echo back the change. So we'll see the
| | 09:18 | difference. So now we'll switch back
over to Firefox and we'll try it out. So,
| | 09:22 | I'll hit Reload and we came back to
same thing. Let's reload it one more time.
| | 09:26 | There it goes. Now we see the change
took place. So the change permissions did
| | 09:30 | take place, we just had to reload our
page an extra time to be able to see them.
| | 09:33 | Now, it's not very convenient to have
to check this octal to figure out whether
| | 09:37 | something is readable or writable to you.
Instead the better way to do it is to
| | 09:41 | use is_readable and is_writable
and use those as test for whether or not
| | 09:50 | we can read or write to the file.
So let's paste in the file name there,
| | 09:53 | so is it readable, or is it writable?
| | 09:55 | It's a Boolean expression. So we want
it to return yes or no and I'll just put
| | 10:01 | that it down here as well. We'll need
our semicolons and we'll need to echo the
| | 10:06 | value just so that we can see it. So
that will just give us a quick is that
| | 10:09 | file readable, is that file writable,
and let's just grab our br tag here just
| | 10:16 | so that it's nice and clean.
All right, let's try that out.
| | 10:18 | So is it readable or is it writable?
Yes, it is readable and it is writable,
| | 10:23 | and we've change this now to be
something like 444, save it, let's go back to
| | 10:29 | Firefox, reload it, yes, it is readable,
no, it's not writable. Now we didn't
| | 10:34 | see the file permission change there.
If we reload a second time,
| | 10:37 | we'll actually see it. It had cached it.
| | 10:39 | So, it did right away know that
whether it was readable or writable. So,
| | 10:44 | is_readable, is_writable are the
methods that we'll use to find out if
| | 10:46 | something is readable or writable, and
we'll use chmod if we want to change the permissions.
| | Collapse this transcript |
| Accessing files| 00:00 | Now that we understand permissions
and how to determine whether a file is
| | 00:03 | readable or is writable, we're ready
to actually do the reading and writing,
| | 00:07 | and the first step in doing that is
learning how to access files in PHP.
| | 00:11 | The PHP function that we're going to
be focusing on primarily is going to be
| | 00:14 | fopen. So we're going to open up a file,
we're going to provide the file name
| | 00:18 | and we're going to tell it what mode
it should open it in. We'll talk about
| | 00:22 | modes in a second.
| | 00:23 | One important thing to note is that
fopen opens up a file whether it exists or not.
| | 00:29 | So it will create it if necessary.
Now just because it's called open,
| | 00:33 | it doesn't mean that the file has to exist
already. We can say fopen and provide a
| | 00:38 | file name that doesn't exist, and
assuming we have provided the right mode to it,
| | 00:41 | it will create the file if it
doesn't already exist. So it will either open
| | 00:46 | the existing file or it will create a
new one. The same command will work for both.
| | 00:50 | So now let's talk about modes. The file
access modes that we have the option of
| | 00:54 | passing in are r, which is read from
the start of the file. This is just
| | 00:59 | reading only and the file must exist
of course if we're going to read from it.
| | 01:03 | So that's going to be reading data in
from a file that's already on our server.
| | 01:07 | The second two are going to be our two
write methods. The first one is going to
| | 01:10 | erase anything that was in the file if
it already existed, or create a new file
| | 01:14 | if it didn't, but we're basically going
to be starting with the blank file and
| | 01:18 | we're going to be at the beginning of
the file ready to start writing, and
| | 01:21 | the third one is append or write to the end.
| | 01:23 | So that's going to be useful for
something like a log file where we just need
| | 01:27 | to add one new entry and then exit the
file. In that case, the w method would
| | 01:31 | not have been suitable because it
would have truncated everything that there before.
| | 01:35 | Just wiped it out.
| | 01:36 | Now there is a fourth mode that I want
to mention to you which we won't use a
| | 01:39 | lot but its x, and that is write from
the start and the file can't exist.
| | 01:44 | So essentially, what that does is keep us
from accidentally overwriting another file.
| | 01:49 | It says start writing a new file,
but object if this file already exists,
| | 01:54 | do not overwrite it.
| | 01:55 | Now all four of these modes also offer
an alternative version. Instead of just
| | 02:00 | r for reading from a file, what if we
want to read and write from the file
| | 02:04 | while we're in there? Well, for that
we have a plus version. So for the read,
| | 02:08 | we can both read and write if we put
the plus after it. For the w+, it's going
| | 02:12 | to truncate us, put us at the start,
but then we can go ahead and read and
| | 02:16 | write from there and append will put us
at the end of the file but also enable
| | 02:21 | us to both read and write from
it and the same is true for x.
| | 02:24 | So those plus versions are the ones
that let us move around in the file and
| | 02:27 | read a little bit, write a little bit,
and then keep moving on. If we're just
| | 02:31 | going to be reading though, we're just
going to be writing, we want to stick
| | 02:34 | with the non-plus versions.
| | 02:36 | Now before we actually put fopen into
practice, there is one more thing that I
| | 02:39 | want to make sure I caution you about,
which is file line endings. There is
| | 02:43 | another difference between the two
platforms, Windows and then Mac, Linux and
| | 02:47 | Unix, is the kind of line
endings that end each line of a file.
| | 02:51 | Windows uses, \r\n. Now you may say,
well, I've never seen that in a file.
| | 02:56 | A lot of times, they get suppressed and hidden
by your word processor or whatever you are
| | 03:01 | looking at, but that how it knows to
wrap around is that it has those characters
| | 03:05 | in there and then it just hides them from you
and just goes ahead and moves to a new line.
| | 03:08 | Well, Mac, Linux and Unix use \n instead,
so you can see how if we're reading
| | 03:12 | in a file that has the wrong line endings,
it might cause problems depending on
| | 03:16 | which platform we're on.
| | 03:17 | So there is an additional mode
modifier that we can pass in as well as the r,
| | 03:22 | the w, and the a, and the x and that
is either t or b. Now b is binary mode
| | 03:28 | which says basically don't translate.
Just take what I give you and write it to
| | 03:32 | the file without making any changes
and b is in the default on all platforms
| | 03:35 | since PHP 4.3.2. Before that, it
depends on exactly which platform you are on,
| | 03:41 | which version of PHP. You couldn't
really be sure, but for a while now it's been
| | 03:45 | standardized on b.
| | 03:46 | Now t is really for use by Windows users.
If you need to use Windows line endings
| | 03:52 | when you are writing a file,
so that let's say another Windows
| | 03:55 | application can open it up later,
you'll want to use the t modifier, and that
| | 04:00 | will then make sure that everywhere you
have set /n in our PHP script, it will
| | 04:04 | quietly just put down \r\n for you
so that it's ready for your Windows application.
| | 04:10 | Now the same thing, if a file was
created originally in a Windows application,
| | 04:14 | you can use t to translate and make
sure you get those correct line endings.
| | 04:18 | So I just want to make sure that I at
least tell you about that so that if you are
| | 04:21 | having problems on Windows,
with having the wrong line endings,
| | 04:24 | you'll know what the solution is.
| | 04:25 | Now let's get some experience using
fopen. So I'm going to open up TextMate and
| | 04:30 | let's create a new file and I'm
going to save it in my btB_sandbox as
| | 04:36 | file_access.php. In this file, we're
just going to concentrate on getting
| | 04:41 | access worked out.
| | 04:43 | So we already have talked about the
fact that it was going to be fopen that
| | 04:46 | we would be using. So let's specify
the filename and let's just call it
| | 04:51 | file_test.txt. It's a nice simple name
so then we're going to want to pass that
| | 04:57 | file name in to fopen. Then we're
going to need to pass in the modifier.
| | 05:02 | So in this case, we're going to create
a new file called file_test and write to it.
| | 05:06 | So I'm going to use w. If I had
used r, it would fail because file_test
| | 05:10 | doesn't exist but here is also where I
could pass in b or t if I wanted to add
| | 05:16 | those additional modifiers or plus, but
for now I'm just going to be using the w,
| | 05:20 | and fopen also returns a handle as a value.
| | 05:24 | Now you remember we talked about
handles with the database connections.
| | 05:28 | When we did database connection to MySQL,
it returned a handle and the reason why that
| | 05:33 | handle was useful was because then we
could close it and that's exactly what
| | 05:36 | we're going to do here as well. We're
going close our file by referencing its
| | 05:40 | handle. So it just a reference to the
file that we have opened so that we can
| | 05:43 | continue to talk about it after it's opened.
| | 05:46 | Now it's a good practice to always
close your files. PHP will close all files
| | 05:51 | at the end of the code execution on
its own, just like it closes the database
| | 05:55 | connections but you want to close them
yourself so that you don't accidentally
| | 05:58 | write to the file again when you don't
mean to. It's just a good practice.
| | 06:01 | If you are opening up the file, let's go
ahead and close it when we're done;
| | 06:04 | if we need to reopen it,
we can reopen it and so on.
| | 06:07 | So let's go ahead and try this and
it's going to give us some problems but
| | 06:10 | it will illustrate a couple of points
that I want to make. So I'm just going to
| | 06:13 | save file_access and I'll
open up Firefox and we'll go to
| | 06:19 | localhost/btb_sandbox/ and it'll be
file_access.php that we'll load up.
| | 06:26 | Now instead of working, it gave us an
error saying that fopen failed to open
| | 06:31 | stream. That means that it failed to
open the file; the stream is just the data
| | 06:34 | stream where it's going to write to
the file. So the permission was denied is
| | 06:38 | the error why and so therefore, fclose
couldn't work because it had an invalid
| | 06:42 | resource because we never opened it up.
| | 06:44 | So this raises one issue that I want
to jump to right away which is that it's
| | 06:48 | always a good idea, I think, to bracket
this inside if statements. So we say if
| | 06:54 | the handles succeeds, then what do we want to do?
And in this case, we'll just simply close it.
| | 07:00 | That's all we want to do.
If not, then we'll just have
| | 07:06 | something like echo "Could
not open file for writing."
| | 07:14 | So I think that's a really good habit
to be in because it's going to prevent
| | 07:17 | some of what happened here. Now if I do it,
it says it "could not open file for writing."
| | 07:20 | I get something that's
a little more meaningful.
| | 07:22 | Now I'm still getting my errors
because I'm in development mode and I told my
| | 07:26 | PHP file to show that to me but in
production, I would still be able to see
| | 07:29 | something like "could not open file for
writing" and we can also take a different
| | 07:33 | action here if we wanted to. But now
let's deal with this permissions issue and
| | 07:36 | actually fix what's going on
here with this permission denied.
| | 07:39 | Now if it did work for you, than
that's great. But if didn't, like for me,
| | 07:43 | and I'm guessing it probably didn't,
you will need to go to Terminal and in
| | 07:47 | that btb_sandbox file, we need to
see what the permissions are for the
| | 07:50 | directory that we're trying to
create this file in. We talked about
| | 07:53 | permissions, so I'm going to scroll
up here at the top. This is the current
| | 07:56 | directory we're in. It's the period.
dot-dot is the directory one back from here.
| | 08:01 | Period is this directory that
I'm in right now, btb_sandbox. These are
| | 08:07 | its permissions.
| | 08:08 | So you can see that as the user, Kevin,
I have the ability to read and write files to it
| | 08:13 | but the web server, which is not
running as Kevin, it's running as www,
| | 08:18 | doesn't have enough privileges
to write. It can only read from these files.
| | 08:22 | So we need to give it privileges
on this directory so that it can do that
| | 08:26 | and you remember how to do that.
| | 08:27 | I don't think I need to tell you but
we'll do it together. sudo chmod and we'll
| | 08:32 | just go ahead and make it 777 so it
will open up wide up, and you also could
| | 08:35 | change the owner if you wanted. I'm
just going to open it wide up so that
| | 08:38 | this directory now is fully able to be
read and written to or execute anything
| | 08:43 | that's in it. And the way I talked
about this directory, that I could
| | 08:46 | either navigate back a directory and
then say okay, the btb_sandbox file, or
| | 08:51 | I just can use that period and that
will say this directory that I'm in right now.
| | 08:54 | And it wants my password because
I did the sudo and then let's just do
| | 08:59 | ls -la one more time. We'll take a
look back up here and sure enough,
| | 09:04 | this directory now has rwx, rwx, rwx.
So now, it is a writable directory.
| | 09:11 | Let's switch back and let's just try
our file_access again and there it is.
| | 09:15 | It worked fine. If we come back over here
and take a look, we should have gotten
| | 09:19 | file_test.txt and there it is. It created it.
| | 09:22 | So it's important I think to use that
if/then statement, it's important to
| | 09:26 | always close your files and you want
to make sure that any file that you are
| | 09:29 | going try and write to is going to be
writable. You just need to make sure that
| | 09:33 | the file itself is readable. Then in
case of writing, when you make sure that
| | 09:36 | the directory we're going to write to
has permission to write to it. In the
| | 09:40 | next movie, we'll take a look at how
we can actually write content into the file_test.
| | Collapse this transcript |
| Writing to files| 00:00 | In this movie, I'm going to show you
how to actually write data to the files
| | 00:03 | now that we know how to access them,
and once you have the accessing done,
| | 00:06 | writing to them is dead simple.
| | 00:08 | Now this is the file_access.php file I
was working with. I'm just going to save
| | 00:12 | it as a new file just so we can keep
track of the different stages that we're
| | 00:15 | working on. So I'm just going to do
Save As and instead of file_access,
| | 00:19 | I'm going to call it file_write. There we go.
| | 00:23 | Now I have the other one saved to
refer back to and we can go ahead and make
| | 00:26 | changes here. So I'm still going to
work with the w mode. I'm just going to
| | 00:30 | make note here that this is going to
overwrite anything that was there before,
| | 00:34 | just so that I remember,
and we already have the close.
| | 00:37 | What we need to do now is actually
write to the file and it's super simple.
| | 00:41 | It's just fwrite and then the handle
and then whatever we want to write, abc.
| | 00:48 | And just to make a note here, that's
going to return the number of bytes that
| | 00:53 | were written or false, and it's up to
us whether we want to capture that or not.
| | 00:57 | We can also make an if then
statement if we wanted to check and see
| | 01:01 | whether it succeeded or not.
| | 01:03 | Generally if you can open the file,
writing goes ahead and takes place. So
| | 01:06 | there is no real reason that we need
to capture that data, we usually just go
| | 01:09 | ahead and write the data and
then close it when we're done.
| | 01:12 | So let's go ahead, and to give this a
shot, let's open up our web browser and
| | 01:16 | this one is going to be called file_
write. So there it ran, we didn't get any
| | 01:21 | data there. We haven't learned how
to read from the file yet. So instead,
| | 01:24 | we're just going to come over here to file_
test.txt and open it up and there is our abc.
| | 01:28 | So there it is. It did go in.
| | 01:31 | So if you wanted to write more to it,
we can do the same thing. Let's say
| | 01:34 | fwrite and then the handle again and
this time, we're going to pass in 123.
| | 01:39 | So we'll save it. Again we're going to be
overwriting that file that was there,
| | 01:45 | and let's hit Return. We'll open
it up. I'll test. Now it has abc123.
| | 01:51 | So you will notice that when we issue
another write statement, it just picks up
| | 01:57 | where it left off and that's going to
introduce us to this idea of the pointer.
| | 02:00 | It works like a cursor. So while this
file is opened, it puts the pointer at
| | 02:04 | the beginning of the file and now it's
waiting for us to type, and when you do
| | 02:08 | a fwrite, it types abc for us and then
the pointer is sitting there right after
| | 02:13 | the c just like the cursor blinking,
and then when we say fwrite again, it
| | 02:18 | writes the next bit of text.
| | 02:20 | So keep that idea of the cursor or the
pointer in mind because we'll be looking
| | 02:23 | at it again in a moment. Now more often
and not, I would say that you typically
| | 02:28 | construct all of the content that you
want to output. So let's say 123, we'll
| | 02:33 | put in a new line 456.
| | 02:34 | There we go and then we'll simply just
say all right after we've got all of our
| | 02:40 | content put together, pushed into a
variable with all the line breaks, then
| | 02:44 | we just do write, and we probably would
even have a first one here, we would just
| | 02:48 | simple construct everything and then,
say write it to the file, close the file.
| | 02:52 | So that's a more common way to work.
| | 02:54 | I want to show you this also with the
line endings because it raises another
| | 02:58 | point which is the double quotes
matter (with) and I'm going to say /n, but
| | 03:03 | it's really with any of those special
control characters. Single quotes will
| | 03:07 | put in a literal /n, but the double
quotes say be aware when you are looking at
| | 03:13 | the string that there might be some
special characters like line returns.
| | 03:17 | So the double quotes are important so
I'm going to save that and let's go ahead
| | 03:21 | and just to prove ourselves it worked
one last time, we'll do file_write and
| | 03:25 | then we'll go back and open up file_
test, and there it is abc123 and then 456
| | 03:33 | on a new line.
| | 03:33 | Now there is one thing I want to
caution you about here is that you might be
| | 03:38 | tempted at some point to do something
like a chmod, let's say chmod and then
| | 03:43 | the handle and then let's say 0777
and that would make the file readable,
| | 03:49 | writable, and so on.
| | 03:51 | Well, be careful with this because
the handle doesn't work with chmod, the
| | 03:55 | handle only works with these that
begin with f: fwrite, fopen, fclose. Those
| | 03:58 | are the ones that use the handle, this
one is the actual file name so in that
| | 04:02 | case, this would actually
change it to the write permissions.
| | 04:06 | So just be careful with that the
handle is not universally used, it's only
| | 04:10 | really in these simple cases. Now if
all of that seems a little bit laborious
| | 04:14 | to go to the process of every time
writing a line and then the handle and
| | 04:17 | everything, there is also a shortcut.
So I'll just show you, it's called
| | 04:20 | file_put_contents. So we have a file, I
have the contents all here together in
| | 04:24 | a single string, then I can use file_
put_contents, you pass in the file name,
| | 04:30 | pass in the contents, and it's a
shortcut for opening the file, writing the
| | 04:34 | contents, and closing it.
| | 04:36 | Now that's going to overwrite by default.
So be very careful because it's going
| | 04:39 | to just blow away anything that was
there before with this new stuff and I went
| | 04:43 | ahead and captured the size of what it
wrote just so that I can echo it back,
| | 04:47 | just to show you how that works.
| | 04:49 | So let's try it. It's going to do the
first writing at the top and then it will
| | 04:52 | do the file_put_contents, and we can
just see the difference. So there we are,
| | 04:55 | file of 11 bytes was created and if we
open up file_text now, you will see it
| | 05:00 | only has this 111222333, which was
what I wrote here in this content. All of
| | 05:05 | these got wiped away.
| | 05:06 | So this is the shortcut for doing all
of those steps. If you are just simply
| | 05:10 | going to write a whole file, you can
use this instead of going through all of
| | 05:14 | those steps. In the next movie, we'll
take a look at how we can delete files.
| | Collapse this transcript |
| Deleting files| 00:00 | You have seen how to create and write
to files. Now I want us to see how we can
| | 00:04 | delete files. Deleting is super simple
as long as we keep two things in mind.
| | 00:08 | First, we need to close the files that
we want to delete first. We can't delete
| | 00:12 | opened files. So we have to have that
fclose on any file we want to delete.
| | 00:17 | So if we have opened it we have to close it.
If we never opened it, it's not an issue.
| | 00:20 | It's already assumed to be closed.
| | 00:22 | Second, we must make sure that we have
write permission on the directory or the
| | 00:26 | folder that contains the file. So in
the same way we have to make sure that
| | 00:29 | that directory was writable before we
could create the file, we have to also
| | 00:33 | make sure that it's writable
before we can delete the file.
| | 00:36 | Now in our case, that's already
going to be true but I wanted to mention it
| | 00:39 | because it can be little counterintuitive
because you may think, oh, well,
| | 00:42 | I have write permissions on the file
itself, I ought to be able to delete it.
| | 00:47 | But it's actually the directory that
contains it where it makes a difference as well.
| | 00:50 | So just keep that in mind.
| | 00:52 | In order to test it out, we'll
delete the file test.txt that we created
| | 00:56 | earlier. We'll open a new TextMate
file and we'll go ahead and save it as
| | 01:00 | file_delete.php and we'll put some
PHP tags in there. Now deleting it is as
| | 01:11 | simple as this one command, unlink.
| | 01:13 | Now I know unlink may not sound like
what it's doing is deleting it. That's how
| | 01:18 | you do it. The same way you unset a
variable, we unlink a file. So we'll save
| | 01:22 | that and let's just try it out. Let's
get rid of that filetest. We can always
| | 01:25 | create it again if we needed to. We'll go
into Firefox and file_delete. There it is.
| | 01:33 | Let's take a look and see and our test_
file is now gone. It's not there anymore.
| | 01:39 | So as long as you keep those two
caveats in mind, deleting file is super
| | 01:43 | simple. In the next movie, we'll talk
more about this idea of the file pointer
| | 01:47 | and how we can move the
cursor around inside our file.
| | Collapse this transcript |
| Moving the file pointer| 00:00 | You remember back from the movie
where we learned to write to files that I
| | 00:04 | talked about the idea of the file
pointer, where it's like a cursor in a word
| | 00:07 | processor that we can type and then
it's the cursor sitting there waiting for
| | 00:12 | us to type some more.
| | 00:13 | Well, like a cursor in our word
processor, we also have the ability to move
| | 00:16 | that pointer around inside the file
to write to different places within the
| | 00:21 | file and that's what we're going
to see how to do in this movie.
| | 00:23 | So let's open up a new file in
TextMate and I'll go ahead and save it as
| | 00:28 | file_pointer.php and the first thing
we'll need to do is the same kind of
| | 00:36 | create file and write to a file that
we have done before, nothing really that
| | 00:40 | special there.
| | 00:41 | So in order to find out where a
pointer is right now, after we have done this
| | 00:45 | writing, we can use ftell. We'll pass
in the handle again and that will return
| | 00:51 | the position. So I'll just call it pos.
That's the position of our cursor or a
| | 00:56 | pointer after having typed the 7, 8, 9 there.
| | 00:59 | So now we can use that as a reference
for moving around. We can do that with
| | 01:04 | fseek. Now we're not doing a search,
what we telling it is move to this new
| | 01:09 | location, seek this new location for
us. So handle and then we also need to
| | 01:15 | tell it what position it's going to go to.
| | 01:16 | So 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:28 | something else. I'll just put in abcdef.
It's so common that if we want to go
| | 01:32 | back to the beginning of the file we
also have rewind available to us. And just
| | 01:37 | pass in the handle and it will rewind
back to the beginning of the file and
| | 01:41 | let's just put in something else here, xyz.
| | 01:45 | So let's go ahead and just try this
and see what happens. And so what we're
| | 01:49 | doing is we're writing a little bit to
the file, finding up a cursor position,
| | 01:52 | moving back six characters, typing
something else, going back to the beginning
| | 01:56 | of the file and putting in
something else and then closing the file.
| | 01:59 | So let's try it. Let's go back to
Firefox and you will remember that this is
| | 02:04 | going to actually create the file for us.
We deleted it in the last movie. But
| | 02:08 | it will create a new file called
filetest.txt and if we open it up, look what
| | 02:12 | we get. We did get the moved around text.
But notice that it overwrote what was there.
| | 02:19 | So just to be very clear, this has
nothing to do with what mode what we put it
| | 02:23 | in. It's not because we're w mode or we
have x or a anything like that. This is
| | 02:28 | the behavior. When we move around the
pointer that cursor will over type. So if
| | 02:32 | we want to capture what was there, we
have to first read that data in, hold it
| | 02:37 | in the variable and then
re-output it at the end.
| | 02:39 | So if we really wanted to put xyz at
the beginning and not destroy what was
| | 02:43 | there, then we have to capture it,
put this in, and then re-output what was
| | 02:50 | there before. So that's the first
thing that I want to caution you about. So,
| | 02:53 | Beware, it will overtype, okay,
so that will remind us about that.
| | 03:00 | The second thing that I want to point
out here is that those modes do matter a
| | 03:04 | little bit because the a and the a+
modes, the append modes, will not let us
| | 03:09 | move the pointer. They put it at the
end of the file and they force it to stay
| | 03:13 | at the end of the file. They force us to append.
| | 03:15 | The R and the Ws are ones that allow us
to move around and read and write from
| | 03:20 | different places. So if we want to be
able to append but then we might also
| | 03:25 | want to jump back to the beginning. We
need to use something like r+ as one of
| | 03:30 | our options and then we can go to the
end of the file, write something, jump
| | 03:34 | back to the beginning and write something else.
| | 03:36 | So those are just the two things that
you need to be careful of. But with that
| | 03:39 | ftell, fseek and rewind, you will be
able to move around to different points in
| | 03:43 | your file and write data.
| | 03:45 | Now typically we're only going to want
to write it either at the beginning or
| | 03:47 | at the end or just write the whole file.
But at least, now you know how to move
| | 03:51 | that pointer around and
the way the pointer works.
| | 03:53 | In the next movie, we'll take a look
at how we can read back data that was
| | 03:56 | previously written to a file.
| | Collapse this transcript |
| Reading files| 00:00 | Now that we have seen how to write
file and how to move the file pointer
| | 00:03 | around, we're ready to learn how
to read back information from files.
| | 00:07 | So to start this out I want to open up
file_write.php, just so we have that as
| | 00:11 | a reference for the steps that we used
to write a file because that's going to
| | 00:14 | be very similar and then I'm going to
also open a new PHP document and
| | 00:18 | I'll save that in my sandbox and
I'll just call it file_read.php.
| | 00:25 | So just like before we'll have our PHP
tags and let's go ahead and specify the
| | 00:29 | file we want. We'll have it be the same
thing, filetest, again. Opening the file
| | 00:34 | is going to be pretty much the same
thing except that instead of overwriting,
| | 00:38 | now we want to read and that's that r option.
| | 00:42 | So we'll open it up. I'll go ahead and
close my curly braces so I don't forget.
| | 00:47 | And then inside here we need to
actually do the reading and just like we used
| | 00:50 | fwrite over here, we're going to have
something similar. We're going to have
| | 00:54 | fread that we'll read back in. So we'll
pass in the file handle that we created
| | 01:00 | and the other option that we need to
pass in is argument for fread is how many
| | 01:04 | bytes do we wanted to read. I'm just
going to say three for now. And then I'll
| | 01:07 | just make a note here that
each character is one byte.
| | 01:13 | Now that's true in typical English
language. We have one-byte characters.
| | 01:18 | In something like Chinese, it's multi-
byte characters, so it is not necessarily true.
| | 01:22 | But for the English language
with a typical Roman alphabet,
| | 01:25 | each character is going to be one byte
long and then the other thing of course
| | 01:29 | we need to do is -- we don't want to just
read it, we want to do something with that read.
| | 01:33 | Now we could just echo it out. That's
perfectly valid. But I'm going to go ahead
| | 01:36 | and just capture in a variable
content and then we want to, of course, make
| | 01:40 | sure that we do our fclose that we
normally do to close up the file once
| | 01:44 | we're done with it.
| | 01:45 | So now we have read three bytes in or
three characters and we have assigned
| | 01:49 | them to content. So in order to take a
look at that we could just simply put in
| | 01:54 | echo content and we'll be able to see
those results back. Let's try that out.
| | 01:59 | So we'll go into Firefox, local
host/b2b_sandbox and we'll open up
| | 02:04 | file_read.php. And sure enough it comes
back with xyz. And I'll just move this
| | 02:10 | out of the way so we can bring up
filetest.txt. Yours might have something
| | 02:14 | different. For me it brought back
these three characters. Those three bytes.
| | 02:19 | If we were to bring back more, let's
say we brought back six characters--
| | 02:24 | let me close that up-- Firefox reloads
the page. You will notice that it all comes
| | 02:27 | through as one line. It didn't break to
a new line. That new line character is
| | 02:31 | actually in there as part of the output.
| | 02:34 | What we need to do in that case is to
actually use to nl2br tag and that is
| | 02:41 | basically saying that we're going to
take each new line and turn it into a br tag
| | 02:45 | so that HTML will show it properly
and now we can see the break as
| | 02:49 | we would expect. So instead of just
getting this, we end up getting the two-line version.
| | 02:55 | Now I'm sure you are wondering what
about if we don't know how many bytes a
| | 02:58 | file is? We want to still be able to
let's say read an entire file regardless
| | 03:02 | of how long it is. But with that we can
use filesize. So fread handle and then
| | 03:08 | we'll ask the file, tell me what your
file size is. How many bytes are you?
| | 03:12 | And so filesize comes in useful by
telling us the total number of bytes.
| | 03:15 | We will now read the file until we
get to that total number of bytes, then
| | 03:19 | we'll know we have everything and then
we can do the same echo back and let's
| | 03:23 | go ahead and put in the nl2br. We'll try
that out and now we get in the entire file.
| | 03:29 | Now back over here on the file writing,
we had file_put_contents and that was a
| | 03:34 | shortcut for us that would do the open,
the writing and the close. Well,
| | 03:39 | we have the same kind of thing that
we can do for reading and that is
| | 03:43 | file_get_contents. So it will say get
the contents of this file, get everything
| | 03:47 | there is. It takes care of filesize
and all that for us, reads to the end of
| | 03:51 | the file and then we have the ability
to just echo that back. If we switch back
| | 03:55 | over to Firefox and we reload the page,
you will see that it did.
| | 03:57 | I didn't put the nl2br there,
but we know what that does.
| | 04:01 | Now the last thing that I want to make
sure that I'll show you is incremental reading.
| | 04:05 | Now we have already seen how
we can do incremental reading by reading
| | 04:08 | a few bytes but another thing that's
really useful is to be able to read
| | 04:11 | one line at a time. So for example,
if we had tabbed delimited data,
| | 04:15 | so we're looking at an export that's been done
of a attendees or products something like that,
| | 04:22 | we could take that value and we can
look for the first name, the last name and
| | 04:25 | everything as we parse through each line,
and each one has a line return at the end.
| | 04:29 | So it comes back. So we obviously
want to just get a line essentially and
| | 04:33 | in order to do that what we use is
fgets content = fgets($handle) and that will
| | 04:42 | then get one line of the file and
that's the maximum amount that it will retrieve.
| | 04:47 | Now obviously in a case like this,
we're going to want to not just get one line back
| | 04:51 | perhaps but still go through and
get the entire file and the way we can
| | 04:56 | also do that is by using while statement:
while, not f for file, eof for end of file.
| | 05:04 | So while we're not at the end of
the file and we need to pass the handle
| | 05:08 | again so that it knows which file
we're talking about, then go through and
| | 05:13 | perform this loop.
| | 05:15 | Here we go and of course content then
will need to be built up over time.
| | 05:19 | We don't want to just keep replacing it
and we know how we could do that with
| | 05:22 | something append. So content starts
up being equal to an empty string and
| | 05:26 | each time we'll add each line to it.
| | 05:28 | Now obviously if we're doing something
like this we'll probably want to do some
| | 05:30 | processing to it. We'll probably want
to get this value, then parse it, then work with it,
| | 05:35 | then store it to content. But
what I want to just make sure that you saw
| | 05:38 | was how this feof works, so that we
can say loop through until you get to the
| | 05:43 | end of the file. It essentially does
the same thing as this filesize does, but
| | 05:47 | instead of providing a number of
bytes it just keep getting a line,
| | 05:50 | keep getting a line, keep getting a line.
If you hit to the end of the file then
| | 05:54 | stop whatever you are doing. And that's
all we need to be able to read in files.
| | 05:57 | We'll go back over and just try it
one more time here. We didn't actually
| | 06:01 | output anything here at the end.
Let's just do that one last time so you can
| | 06:04 | see that worked too.
Here we go and there we are.
| | 06:08 | So now we know how about successfully
write file and how to read from them.
| | 06:12 | In 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:00 | To round our discussion about files, in
this movie I want us to take a look at
| | 00:03 | how we can get some of the information
about the file details. We have already
| | 00:07 | seen file size. We're going to look at
meta information that we can get about each file.
| | 00:12 | So we'll got to TextMate and we'll
just open up a new window. I'll save it as
| | 00:17 | file_details.php and that's in my
btb_sandbox. We'll start our PHP tags.
| | 00:25 | To start this off, let's go ahead and
just put in the filesize, just so that
| | 00:28 | we remember how to do that. So that it
just simply the filesize and then we pass it
| | 00:32 | in the file name that will echo back to us.
| | 00:35 | The next one that I want us to look at
is the modification times about files.
| | 00:40 | There are actually more than just one
number associated with this. There are
| | 00:43 | actually three different ones and
we're going to get them using filemtime,
| | 00:47 | filectime and fileatime. I'll just put
colons after that to clean that up a little bit.
| | 00:52 | The filemtime is the last time
that the content of the file was modified.
| | 00:58 | So the file modification time.
It's the content inside the file.
| | 01:01 | We also have filectime. Some people
mistakingly think that that's the creation time.
| | 01:07 | That's not the case. It's the
last changed time, when the file was
| | 01:11 | changed. We don't have access to the
creation time. So it's the last changed time
| | 01:15 | and that's both changing the
content or the meta data, the permissions,
| | 01:20 | the owner, the group that it belongs
to, all those sort of things that
| | 01:23 | we learned how to do the chmod and chown.
That includes those in filectime.
| | 01:28 | The last one is fileatime. It
actually keeps track of when a file was last
| | 01:33 | accessed. So not only making those
changes, like we do with ctime or mtime,
| | 01:40 | but in addition anytime we read the file,
anytime we read back the contents of the file,
| | 01:44 | it updates that access time.
| | 01:46 | So let's try all of those. Each one of
them is going to take the file name as a
| | 01:51 | argument and it's going to return back
a UNIX time stamp. We saw how we can use
| | 01:56 | string for time, right here, strftime
and that will turn that time stamp into
| | 02:01 | something that we can see. So let's
just try that on this file name and see
| | 02:05 | what we have got.
| | 02:06 | Yours will almost certainly be
different than mine, but you will be able to see
| | 02:09 | the difference between the times
that your file was modified, created, or
| | 02:13 | accessed. So I'll just open up
Firefox and let's go to file_details.php.
| | 02:21 | So there we go. The size came
back as 11. That's the first one.
| | 02:25 | Then my modification times were all the same.
So my file at 12/10/2008 at 13:05 is when
| | 02:33 | my file was changed and updated.
| | 02:36 | Now you may have different values or
you may have the same value for all of those.
| | 02:39 | One way that we can modify
those times is with the touch command.
| | 02:45 | So touch($filename) is going to say
update those to the current time. We can also
| | 02:52 | pass in some other additional arguments
to tell it what time it should set it to,
| | 02:55 | but what we're going to do for now
is just say set it to the current system time,
| | 02:59 | just sort of reach out and flip all
of these times to be the current time.
| | 03:04 | Then let's reecho it, just to
see what time we get back. We'll go back
| | 03:08 | and we'll reload the page.
| | 03:09 | Now just reload it once at first and
notice what happens. So I hit Reload.
| | 03:14 | Now, the times didn't change, the times
are the same. If I reload it again,
| | 03:18 | watch what happens though. They changed.
The reason why is because there is some
| | 03:23 | caching going on. These values are being
stored the first time it goes and finds them
| | 03:28 | and touch does not change that.
It does not flush the cache.
| | 03:32 | So when we go here and we output it a
second time, it's bringing up the cached values.
| | 03:37 | So just because we touched it does
not mean that we did not get the cached
| | 03:41 | values back again. So we're getting
old information at this point that is
| | 03:43 | outdated. When we reloaded the
page, then we got the new times.
| | 03:48 | So I just wanted to show you by doing
it twice, so that you see that it is a
| | 03:51 | cached value. If you use touch, you
may not get the right information here.
| | 03:55 | You might be getting some old data back.
| | 03:58 | So just to show you the difference,
let's go in and actually open up
| | 04:01 | filetest.txt and let's just make a
change. Let's say ghi. Here we go and
| | 04:07 | it's going to want me to put in my master
password and that's because I'm not the
| | 04:11 | owner of the file. WWW is the owner.
So that's why it came up and asked me for that.
| | 04:16 | You may need to do the same
kind of authentication or you can do this
| | 04:19 | with another file where you do
still have permission to do it.
| | 04:22 | So let's try that out now and just
see now that we have changed the content,
| | 04:24 | everything changed. If we instead go
through and do a read, let's wait one
| | 04:30 | second and after a good minute has
passed, when you are pretty sure that a
| | 04:35 | minute is over, we can do file_read.php.
We'll read it and then when we come
| | 04:40 | back and do file_details-- They are
still updated so let's turn off our touch
| | 04:45 | first of all. So that it doesn't touch
them anymore. Let a minute pass, then
| | 04:49 | run read and then you should see a
difference. Now I'm not going to wait a
| | 04:52 | whole minute and have you sit here and
wait with me, but you can do that and
| | 04:55 | you will see that
access time is different.
| | 04:56 | You can also try chmod and doing the
chown and see the difference there and how
| | 05:00 | that affects the different values.
You might want to take off this touch,
| | 05:03 | the same way I did just to make sure
that you don't accidentally reset those values
| | 05:08 | when you are trying to see the values
change because of other actions you did.
| | 05:12 | The last thing I want to show you
about the file information that you can get
| | 05:16 | back is pathinfo. So I'm going to take
just the current file that I'm in and
| | 05:20 | ask for its pathinfo. It's going to
return an array. I'm going to call it
| | 05:23 | path_parts, but it's an array of
information that it gives back. Basically,
| | 05:27 | what it does is it takes the
information about this file and parses it,
| | 05:31 | puts all the pieces into an array that
we can retrieve. So here are the things
| | 05:35 | we can retrieve back.
| | 05:36 | I can ask for its dirname. That's the
directory name that it's in and that will
| | 05:40 | return the path all the way up to where
the file is. basename will give me the
| | 05:45 | name of the file with its extension.
filename starting in PHP 5.2 will give me
| | 05:50 | everything but the extension. Of course,
I can ask for the extension just to get that part.
| | 05:54 | So there are some variations you can
look up on path name, some options we can
| | 05:58 | pass to it, but this is essentially
the way it works. It takes a file, parses
| | 06:02 | its path into pieces and then we can
retrieve just those bits of information
| | 06:06 | and PHP knows how to do that for us.
Let's just try that and make sure that
| | 06:09 | it works fine.
| | 06:11 | There we are. It gives us exactly
what we would expect. I think this pretty well
| | 06:15 | rounds out our discussion about files
and we have learned how to write to files,
| | 06:19 | how to read from files
and how to change the permissions.
| | 06:21 | Now we're ready to move on to talk about
directories and that's what we'll do, starting
| | 06:25 | in the next movie.
| | Collapse this transcript |
| Working with directories| 00:00 | Now that we have seen how we can work
with files, let's spend a little bit of
| | 00:03 | time exploring how to work with the
directories that contain our files.
| | 00:07 | We'll start by opening up a new text
file and I'm going to save that as
| | 00:11 | file_directories and I'm going to
still call it file, just so that they stay
| | 00:15 | grouped with the other examples we
have been doing called file. So there we are.
| | 00:19 | We'll put our php tags in the start
and now we're ready to talk about directories.
| | 00:23 | Now, we have already seen a couple of
directory functions before. dirname.
| | 00:27 | We saw to get the name of the directory.
And is_dir. We were doing is something
| | 00:32 | a directory or is it a file. I also
want us to take a look at getcwd.
| | 00:37 | CWD stands for Current Working Directory
and it's a little bit like the file pointer
| | 00:43 | that we have inside of a file
as we're moving around in there.
| | 00:46 | It keeps track of what directory we're in.
Now up until now, we have been just working
| | 00:51 | with everything from absolute references.
Every time we tell it what directory
| | 00:54 | we're talking about, we give it the
full path name. But we also have the
| | 00:57 | ability to move around in the
directory structure from this script.
| | 01:02 | So while file_directories.php is running,
we'll have the abilities to change into
| | 01:06 | a different directory, do some things,
change to a different directory and
| | 01:10 | do some more things there, so that
we don't necessarily have to specify
| | 01:14 | the full file path every time.
| | 01:15 | Let's go ahead and bring this up and
see our current working directory and then
| | 01:19 | in a moment, we'll actually create a
new directory and we can practice moving
| | 01:22 | into there. So file_directories and
you see that it's just the current
| | 01:26 | directory where file_directories.php
is located. That is the current working
| | 01:30 | directory. So let's try creating a
directory. We do that with mkdir, short
| | 01:36 | for Make Directory. So we can do mkdir
and then we'll need to tell it the
| | 01:42 | name of the directory. We'll call it
new and then we also need to tell it what
| | 01:45 | permissions the directory should have.
I'm going to say "0777" and that will
| | 01:50 | tell it to make that directory sort of
wide open for reading and writing and
| | 01:54 | everything. And I'll also just make
a note here that is the PHP default.
| | 01:59 | Now let's go ahead and try it and
let's take a look, let's run our script
| | 02:03 | again. So, now if we come over here,
you can take a look. Here's our folder, new,
| | 02:08 | and if we actually go to our
command line cd Sites/btb_sandbox >ls-la,
| | 02:18 | it will give us a list of all of them and
we can see new. Now notice what happened here.
| | 02:22 | It did not give it the permissions 777.
So you are thinking, wait a minute,
| | 02:28 | did I give you bad information?
Did that not work right?
| | 02:31 | Well, the reason why is that there's something
called umask and it is a mask that is
| | 02:35 | applied to these permissions whenever a
folder is created. And every system has
| | 02:40 | it's own default umask that is
set by default. It's set to be 0022,
| | 02:46 | I believe, which means that it's going
to subtract out 022 from that 777, thus
| | 02:53 | giving us 755. I'll just go ahead and
make it here, default maybe 0022. So this
| | 03:02 | umask gets applied. We can have the
ability to use the umask function to
| | 03:06 | change it. I'm not going to go into
details on how to do that. You can also
| | 03:09 | just use Chmod, which we learned
earlier to change the permissions on this, but
| | 03:13 | I wanted you to understand umask so
that it doesn't stay a mystery to you, as
| | 03:17 | to why when you tell it, hey, create
this with 777, it comes up with 755 for
| | 03:23 | the permissions instead. I just wanted
that to sort of be demystified so that
| | 03:27 | you know how to change it if you need to.
| | 03:30 | Now the other thing that we can do is
we can create directories recursively,
| | 03:33 | recursive 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:52 | create not only new but go ahead and
create test and test2, everything that it
| | 03:57 | needs to create all of those, all the
way down the line. So if we're passing in
| | 04:01 | more than just one, you will want to
also include that true statement there. So
| | 04:06 | let's just try this real quick. I could
go ahead and hide that or run to start
| | 04:09 | script again. So file exist on line 11,
you will see we got an error here for
| | 04:16 | this make directory. So you can see
that this does check whether it exist or
| | 04:19 | not. So if we were using this in a real
script, we would also want to check and
| | 04:22 | make sure that this doesn't already
exist before we tried to do the mkdir.
| | 04:26 | But for our purposes, just to learn
how this works, we already know how file
| | 04:30 | exist works. We saw that at the
beginning of the file chapter.
| | 04:33 | So for now, we can just go ahead and
say mkdir and we'll just accept those
| | 04:36 | errors. So let's take a look here
inside new, there's test and there's test2.
| | 04:41 | So that's really all that is to it.
| | 04:43 | Now let's try changing directories
and we can do that with chdir. So,
| | 04:46 | chdir('new'). That will change into the
new directory and now if we say tell us
| | 04:53 | the working directory, we'll see what
we get back there. Now we're going to get
| | 04:56 | a couple of errors here because those
directories already exist. That's all
| | 04:59 | right. But you will see that now,
our working directory is new. So at the
| | 05:03 | beginning of our script, we had
created a new file and opened the file for
| | 05:06 | writing, it would have been in the btb_
sandbox folder. If we do our chdir and
| | 05:11 | we move our working directory into new,
now when we create a new file it's
| | 05:15 | going to be in the new folder. Because
that's our working directory. It works a
| | 05:19 | lot like a pointer.
| | 05:20 | Then of course, the very last thing
that we want to learn how to do is to
| | 05:22 | remove a directory and rmdir, so it is
like mkdir for make directory, it's 'rm'
| | 05:27 | for remove the directory and then we'll
need to tell it what the directory is.
| | 05:31 | Now again, we'll want to make sure
that the directory exist before we try and
| | 05:35 | remove it, we know how to do that, I'm
not going to do it here. Now also notice
| | 05:39 | that I moved my working directory here.
I'm inside new, so this won't work.
| | 05:44 | Let's try it just to see what happens,
let's do Reload and you will see that I
| | 05:49 | come back here with another error
saying 'No such file or directory' inside the
| | 05:53 | folder that's in now, so it's the
current working directory. If I take away the
| | 05:56 | news since I have changed my working
directory. Now we come back and I don't
| | 06:00 | get the warning and if you take a
look here, you will see that test2 is now
| | 06:04 | gone, test still stays there, it just
removed the directory at the end of that.
| | 06:08 | The very last thing that I just want
to mention to you is that in order to
| | 06:10 | remove a directory, that it must be
closed and empty before you can remove them
| | 06:15 | and there are some scripts that can
help you figure out how to wipe out all
| | 06:19 | directories that already have files by
looking on the PHP website for rmdir,
| | 06:24 | you can just search for it, but that
will give you scripts that other people
| | 06:27 | have written, they will help you to
recursively delete everything that's in an
| | 06:31 | entire directory.
| | 06:32 | Now you know how to create and delete
directories and how to move around in
| | 06:36 | them, we're ready to look at the
contents that are in those directories because
| | 06:39 | a lot of times what we want to do is
find out, hey! What files are actually in
| | 06:42 | this directory? we'll do that in the next movie.
| | Collapse this transcript |
| Viewing directory content| 00:00 | In the last movie, we saw how to
create and move around in directories.
| | 00:03 | Now let's see how to actually view the
contents of those directories, the files or
| | 00:07 | other directories that are contained inside.
| | 00:09 | So for this movie, let's start out by
creating a new file again and we'll save
| | 00:12 | it as file_dircontents.php and we'll
create our php tags. The idea of working
| | 00:24 | with a directory and reading from a
directory is very similar to what we did
| | 00:27 | with working with a file. It's a
lot like fopen, fread, and fclose.
| | 00:31 | We have opendir, readdir and closedir. So the
one thing that you want to do is make sure of
| | 00:37 | course before you start trying to read
from something, that it exists and that
| | 00:41 | is a directory. So here is a
standard example of the process we would go
| | 00:44 | through to output the contents of the
directory. I'm going to have a directory,
| | 00:48 | which I'm just going to use the
current directory that I'm in right now.
| | 00:51 | I'm just using the dot to signify that
that's my current working directory. We also
| | 00:55 | saw how to use getcwd to get the same
information. Then I'm going to check and see
| | 00:59 | is it a directory? If it is a
directory, then we're going to use opendir
| | 01:04 | and we'll get a directory handle, the
same way that we got a file handle back.
| | 01:08 | If we got that successfully, then while
we're able to still get something back,
| | 01:14 | while read directory returns something.
So read directory will return the next item.
| | 01:19 | So there's a pointer that moves
through here, it works a lot like the
| | 01:22 | fgets did, when we were getting each
line one by one. Well, this is getting each
| | 01:26 | item in the directory, one by one
and as long as it returns a filename,
| | 01:29 | then it will keep looping and then we can
do whatever we want with that filename.
| | 01:33 | We can open up that file and look at it,
inspect it, change its permissions.
| | 01:37 | We're inside a loop here. I'm just going
to simply going to have it output the filename.
| | 01:40 | Now notice the filename, not the file
handle. We would have to open the file
| | 01:44 | if we want to have a file handle.
| | 01:45 | So let's go ahead and just try that
for now. Of course, the very last thing
| | 01:49 | we'll want to make sure that we add
after the loop is completely done is to
| | 01:53 | close the directory. So if we're able
to open it, then also let's make sure
| | 01:57 | that we close it at the end. So
let's open up Firefox and we'll look at
| | 02:01 | file_dircontents, and there we go,
we get a list of all of the files. Now,
| | 02:07 | the file name is something I'm outputting
that's here, filename:, and then the file name.
| | 02:12 | So this lists all the files that are
in that directory. Pretty neat, huh?
| | 02:16 | Now, notice that it included dot, which is
the current directory, and dot-dot, which is the
| | 02:21 | directory one back from here, as well
as .DS_Store, which is a private file,
| | 02:26 | a file that normally doesn't show up.
If I come here to the Terminal window,
| | 02:30 | you can see those files are here as well.
So the default listing for a directory is
| | 02:35 | that it includes private files,
it has a listing for itself and it has a
| | 02:39 | listing for its parent directory as well.
Now if we want to hide those, that's
| | 02:44 | a simple matter for us. We just put an
if-then statement, let's say, before
| | 02:47 | we do this part of the loop. If the file
name is a dot, then don't do anything or
| | 02:53 | if it's dot-dot don't do anything and so on.
| | 02:55 | So it's a simple matter of leaving
those out if we want. But by default,
| | 02:59 | those will also be in there. Now,
I also want to point out that because
| | 03:03 | it's a pointer that is moving through
this file as we do each of these read
| | 03:07 | directories, we're moving down to the
next one. If we get to the end or at any point
| | 03:11 | we want to rewind and go back
to the beginning, we have rewinddir,
| | 03:15 | which allows us to jump back to the top of
the file. So we could loop through the whole file,
| | 03:19 | then we could rewind and loop
through it again if we wanted, maybe
| | 03:23 | we're doing table or something and we need
to one whole column and then rewind to do
| | 03:28 | another whole column and so on.
rewinddir would let us do that.
| | 03:31 | It does have to happen, of course,
before closedir because we need this
| | 03:34 | directory handle. Once it's
closed, the handle goes away.
| | 03:37 | There is another way that we can do
the same thing and that is using scandir
| | 03:44 | and what it does is it takes all of
those filenames and puts them in an array.
| | 03:47 | And then it's up to us if want to take
the array and go through and output it,
| | 03:53 | which is what I have done here.
You can see here that I have put in a little
| | 03:56 | bit of code that will leave out those
files that have a dot at the beginning of them.
| | 03:59 | So this is essentially the same thing
as if we had gone through this loop up here
| | 04:04 | but instead of outputting it,
we'll put each item into an array and built
| | 04:08 | an array. Scan directory does
that for us; it's a shortcut. Now,
| | 04:12 | it's not a whole lot shorter but it does make
things like sorting and doing reverse order
| | 04:16 | much easier. So if we wanted to do our
directory in revere order, we could read
| | 04:20 | it all into an array, sort the array and
then output it in the order that we want.
| | 04:25 | So that's where that's going to come in
really useful. Let's try that out real quick.
| | 04:27 | So I just did a Refresh.
Now it's doing the list twice here.
| | 04:31 | Let me put in-- I think it will be
a little easier to see echo "<hr />".
| | 04:37 | There we are. Now we'll see when the one list
stops and then one starts; you will see that the
| | 04:41 | dot-dot files are gone now so it starts
right here at the access_modifiers.
| | 04:45 | So that's done by this simple if-then
statement here. I'm just searching for the
| | 04:49 | position of that string in there to
see whether or not it occurs at the zero
| | 04:53 | position or not.
| | 04:54 | So that's really all there is to
working with directories. We have the ability
| | 04:57 | to create directory, we have the
ability to change directories and move around,
| | 05:01 | we have the ability to see the
contents of the directory. And then once
| | 05:04 | we're able to pull in the contents, we can
do things with it inside this loop here so
| | 05:08 | that we can reach in the file, grab a
bit of data, go to the next file, grab a bit of data
| | 05:14 | and so on and we know how then to delete
the directories when we're done with it.
| | 05:17 | So I think the combination of
working with both files and
| | 05:19 | directories is going to be really
powerful. In the next movie, I'm going to
| | 05:22 | give you an assignment so that you can
put all of this knowledge together and
| | 05:26 | actually try it for yourself.
| | Collapse this transcript |
| Creating a log file: Assignment| 00:00 | Now that we understand the theory of
how to work with files and directories,
| | 00:03 | it's time to put it into practical use
and the way we're going to that is by
| | 00:07 | switching back to our photo_gallery
project. Remember we have been working in
| | 00:10 | the btb_sandbox. And in our photo_gallery
project, we're going to create a log file.
| | 00:15 | Whenever an action takes place, we'll
have the ability to call a function that
| | 00:18 | will log a message to a simple text
file and then via PHP, we'll be able to
| | 00:23 | read back in the results of that log
file as well. So we'll be able to have
| | 00:28 | a simple text file that has recorded actions.
| | 00:30 | Now these could be errors or something
like that. In this case, we're going to
| | 00:34 | be just working on logging when a user
logs in. So every time a user logs in,
| | 00:38 | we'll have a time and date that
that user logged in to our log file.
| | 00:41 | In this video, I'm going over the
requirements for this assignment and some of
| | 00:44 | the steps that you are going to want to
follow, but it's going to be up to you
| | 00:47 | to go off on your own and do it and to
apply everything that you have learned
| | 00:50 | to make this happen and that's really
where I think a lot of learning is going
| | 00:53 | to take place. So, you want to make
sure that you do this and then I'll show you
| | 00:56 | my solution afterwards.
| | 00:58 | The first step is going to be set
up a log directory. So it's going to be
| | 01:01 | in photo_gallery/logs. Now I believe we
created that file earlier. You want to
| | 01:06 | make sure that it does exists and if
it already exists, you will also want to
| | 01:09 | make sure that the web server is set as
the owner. Remember we talked about how
| | 01:13 | the PHP scripts are not going to be
able to make changes to directories that
| | 01:18 | they don't own.
| | 01:19 | So we'll want to make sure that that's
the case and you will probably have to
| | 01:22 | do that outside of PHP and we have saw
to do that earlier, but just to remind
| | 01:26 | you that from the command line, sudo
chown www, if that's the name of your web
| | 01:31 | server and then the location of the
file and if you are in that directory,
| | 01:35 | it's just logs. Otherwise you might have to
specify more of the paths to find that
| | 01:39 | file but that will get the log
directory setup where we're ready to start
| | 01:43 | creating files in it.
| | 01:44 | Once you have your log directory setup,
then we're ready to start looking at
| | 01:47 | the requirements that you are
going to need for this exercise.
| | 01:50 | The first is that we're going to need
to code the log action and we're going to
| | 01:54 | do that in functions.php and the
function will be called log_action and we'll
| | 01:58 | give to two parameters: the action that
we want to log and then a message to go
| | 02:02 | with it. So you want to write that
PHP code to make that happen. So inside
| | 02:07 | there, you are going to want to make
sure that the file exists and if it
| | 02:09 | doesn't, you are going to
want to create a new file.
| | 02:11 | You are going to also want to make
sure that the file is writable and if not,
| | 02:14 | then output an error and when we
add these entries, our log entries,
| | 02:19 | we're going to want to append them to the
end of the file and there is a couple of
| | 02:22 | different ways you can do that. We saw
an Append method earlier. We also saw
| | 02:25 | how we could move the pointer around
to write at the end of the file. So
| | 02:29 | I'll let you choose which one of those
you want to try. The entries go ahead and
| | 02:33 | format like I have got there
in the middle of the slide.
| | 02:35 | Basically, put the date and time and
then the action. In this case, Login and
| | 02:39 | then the message. In this case, it's
kskoglund logged in. That's the username
| | 02:43 | you will have when the person logs in
and remember to make use of the constants
| | 02:47 | we set up, SITE_ROOT and DS for the
directory separator and you want to
| | 02:51 | consider how to handle new lines
because at the end of each line, of course,
| | 02:54 | you will want to go to a new line and
remember that double quotes do matter for
| | 02:58 | using those special characters like \n and \r.
| | 03:02 | If you use single quotes, it will just
interpret them as being literal \n and \r
| | 03:05 | in order to be a new line character,
you need to use double quotes.
| | 03:09 | Once you have done all that, you have got
the log action coded, try using it.
| | 03:13 | Put it into admin/login.php and see if
you can actually log something to the file.
| | 03:19 | Then you go into the log file, take a look
and see if it's there. If not, wipe it out.
| | 03:23 | Try again until you get it right.
| | 03:25 | Now in a lot of instances, it might be
fine to just have that log file sitting
| | 03:28 | there. We could open it with the text
editor whenever we want to see it.
| | 03:31 | We're also going to let our application read
it in because we know how to do that too.
| | 03:34 | So the next step in our exercise will
be to read back in the log file from a
| | 03:38 | PHP page. Just like all the other
Admin pages, we're going to first confirm
| | 03:42 | that the user is logged in already
because this is not something that
| | 03:45 | non-logged in people should be able to
do and we're going to then locate that
| | 03:48 | log file and we're going to make sure
we use SITE_ROOT and DS, the directory
| | 03:52 | separator again. We're going to check
if the file exists or not, check if its
| | 03:55 | readable or not and then if its
readable, read its contents in and we saw a
| | 03:59 | couple of way to do that, I'll let you
choose on how to do it and then output
| | 04:02 | those entries to HTML so that we can
view them in the browser and there are
| | 04:06 | several ways that you can output those.
We saw nl2br for new line to <br> tag,
| | 04:12 | you can use that or you can use
cascading Style Sheets or an HTML table or
| | 04:17 | something like that, but the overall
ideas that we want to have all those
| | 04:20 | entries show up in our HTML page.
| | 04:23 | Once you have got those two parts
together, I want you to round out the
| | 04:26 | functionality of this log file by
creating a way for us to clear the log file
| | 04:29 | out and so in that logfile.php, where
we're viewing the file, we're also going
| | 04:34 | to add a link that just says "Clear the
log file" and it's going to request to
| | 04:37 | URL "logfile.php?clear=true" and
then at the top of that same file,
| | 04:43 | before we display the results of
the file, we'll say well, check and see.
| | 04:46 | if($_Get['clear']=='true'), then clear
the logs and then after you have cleared them,
| | 04:52 | we'll want to make another log entry
that let's us know that the log was cleared.
| | 04:56 | So you want to clear it out and put
one entry in there letting you know that
| | 05:00 | the logs were cleared. Now that's the
end of your assignment that you need to
| | 05:03 | go off and work on and in the next
movie, I'll show you the solution.
| | 05:06 | You can peek at the solution if you run
into problems, but even better would be for
| | 05:09 | you to go back to the movies where we
originally discussed those topics and see how
| | 05:13 | to do it there and then apply it and
see if you can get it working and as extra
| | 05:17 | credit, if you get all of that working
and you want to try something else,
| | 05:20 | try creating a Logger class.
| | 05:21 | We have talked about classes, we have
talked about files. We're going to now
| | 05:25 | have seen how to work with the log
file. You have everything you need to go
| | 05:28 | ahead and bundle all of this
information together into a Logger class that
| | 05:32 | we could then potentially use in all
of our applications going forward.
| | 05:35 | I'm not going to show you the solution to
that but that's just an extra exercise
| | 05:39 | if you want to try it on your own.
| | 05:40 | So give it a shot and in the next
movie, I'll show you my solutions.
| | Collapse this transcript |
| Creating a log file: Solution| 00:00 | In this movie, I'm going to show you
the solution that I came up with to the
| | 00:03 | Create a Log File assignment. Now if
you haven't completed that assignment yet,
| | 00:06 | I encourage you to try it on your own
first. It's one of the best ways you are
| | 00:09 | going to learn how to put all of these
pieces together and then once you have,
| | 00:13 | you can review my solution and see how
close we are. They may not be exact and
| | 00:16 | that's okay. There are a lot of different
ways that you can approach these problems,
| | 00:19 | but I'll show you mine.
| | 00:20 | So the first requirement of the
assignment was to make sure that we had a logs
| | 00:24 | directory and to make sure that it
was available to the web server.
| | 00:28 | In this case, I made sure that the web
server actually owns that file. www is my web
| | 00:33 | server. Yours might be something else.
| | 00:35 | The other way to approach, it would be
to set the permissions on that file to
| | 00:38 | something different. Mine are set
so that the owner has read and write
| | 00:41 | privileges to it. Other people just
have read privileges. We could change those
| | 00:46 | and if it wasn't the owner, then we
certainly would need to make everyone,
| | 00:49 | for example, be also read and write,
but once we have the log file setup then
| | 00:53 | we're all set to move on
to the second requirement.
| | 00:56 | The second requirement was for us to
code this log action inside functions.php
| | 01:01 | and you will see that the first thing
I did was I had figured out where that
| | 01:04 | log file ought to be, even though it
doesn't necessarily exist yet, where will
| | 01:08 | it be and I used SITE_ ROOT and DS to
say well. It's in the logs directory and
| | 01:12 | it will be called log.txt.
| | 01:14 | Now, the way I decided to write the
file was using Append. Now Append, one of
| | 01:21 | its features is that if the file does
not already exist, it will create it for
| | 01:26 | you. If it does exist, it will just
grab it, open it up and start appending at
| | 01:30 | the end. Well that's nice because it
actually saves me from having to check
| | 01:33 | whether the file exists or not. I went
ahead and did a File Exist check here
| | 01:38 | and said well, let's check and see
if it's new. And the reason why it is
| | 01:41 | because once I'm done with all my
writing, I just set it to do a Chmod at the
| | 01:45 | end to say well, make sure
that the log file is 0755.
| | 01:49 | Now that's an optional step, you don't
have to do those two steps. I went ahead
| | 01:52 | and did it. Append has that
functionality built-in already where it will either
| | 01:57 | create a new one or append at the end
of the old one. So I open it up in Append mode,
| | 02:01 | so I'm all set. The pointer's
at the end of the file ready to write.
| | 02:05 | I went ahead and figured out what my
time stamp would be using the strftime
| | 02:08 | function, using just PHP's time. We
saw how to do that earlier and then I
| | 02:14 | assembled the content that I wanted to
output altogether into a variable and I
| | 02:18 | said we're going to put the time stamp,
then a pipe, one of the upright bars,
| | 02:22 | the action, colon and then the
message and then new line at the end.
| | 02:27 | Notice that \n and that's in double quotes.
Double quotes are important because
| | 02:33 | we're using the special character and
then I write that content to the file,
| | 02:37 | close the file and we're all set.
| | 02:38 | Now of course, if it wouldn't open
up for some reason, then we say just a
| | 02:42 | simple error message "could not open it
up." So that's all there is to writing
| | 02:46 | the log action and now we can call
that action whenever we want and here
| | 02:51 | we'll do that in our login.php. We just
simply say log_action and then Login.
| | 02:56 | We'll call and then what are we going to
pass in? We'll pass in the username and
| | 03:00 | the logged in as the message
and that's all there is to it.
| | 03:03 | Now we can log things to log file that
easily. So that takes care of the second
| | 03:06 | part of the assignment that I gave you,
which was to write that log action and
| | 03:09 | use it and then the next thing we want
to do is be able to read that log file
| | 03:13 | back in. I went ahead and said, where
we should be able to find the log file?
| | 03:17 | Now since we would have this in
both places potentially. This could be
| | 03:20 | something that we would setup in our
config so that we could look in our
| | 03:23 | configuration and know where the log
file is instead of having to repeat it
| | 03:27 | several times throughout our
code, but for now, this will do.
| | 03:29 | Now we'll come back to the GET['clear']
part that was the fourth part of the
| | 03:33 | assignment. The third part is to read
in that log file. So we know where the
| | 03:36 | log file is. So down here in the HTML,
I have got a bit of PHP that's going to
| | 03:40 | check to see does the file exists, is
it readable and can we open it? So if all
| | 03:46 | three of those things will turn true,
then great, we can keep going.
| | 03:50 | We're ready to read in the file. But if it
doesn't exist or if it's not readable or
| | 03:53 | if we have a problem opening it for any
reason, we'll go down here to the else
| | 03:58 | statement, "Could not read from the {$logfile}."
| | 04:00 | Now let's assume that it works, in
most cases it should. I decided to do it
| | 04:05 | with some CSS. So I went ahead and had
a <ul> just for an unordered list and
| | 04:10 | then each of the items I decided it
would be li's. So there will be a nice HTML
| | 04:14 | list that we can potentially
style them with Style Sheets.
| | 04:17 | So here is the important part though, I
do the loop until we get to the end of
| | 04:21 | the file, while not equal to the end
of the file, get each line and I decided
| | 04:25 | to use fgets. You could have used
fread or something. That would have been
| | 04:28 | fine. The reason fgets works so well
is because we know that each line in the
| | 04:33 | log file has a new line return after it.
We don't necessarily know how long it
| | 04:36 | is but we know that there is a new line.
So fgets handles that for us. It says,
| | 04:41 | get the next bit of
information until you get to a new line.
| | 04:44 | So for line-by-line files, fgets is
the best way to go. And then I went ahead
| | 04:49 | and added a little bit of text here,
an If statement before I actually output
| | 04:53 | the entry. The reason I decided to do
that was that this makes sure that there
| | 04:57 | is not a new line return without
something else there and I discovered that I
| | 05:01 | needed that one. I started clearing
the log file. Sometimes I would have an
| | 05:05 | extra new line return and I was
getting an <li> tag with nothing in it and I
| | 05:10 | said well, it would be a nice
improvement here if I simply just trimmed any
| | 05:13 | white space from entry. And if there
is something there besides just nothing
| | 05:17 | after we have trimmed away the
white space, then output the entry.
| | 05:21 | That's optional.
| | 05:23 | Then the fourth part of this
assignment was this clearing the log file,
| | 05:27 | so I pretty much gave you what the link
tag should be to make that happen. The part
| | 05:31 | that you really need to code is up here,
if($_GET['clear'] == 'true'). Let me
| | 05:36 | just expand this and you will see file_
put _contents is what I decided to use
| | 05:42 | and I told the log file put the
contents nothing in that file.
| | 05:47 | So I wanted to use file_put_contents
here, so you could see a place where it's
| | 05:50 | really useful. Remember this a
shorthand way that we can write to the file. Now,
| | 05:54 | it could have also opened up the file
using Overwrite and written in the file
| | 05:58 | logs cleared. I decided to go ahead and
deal with this one line, clear out the
| | 06:02 | log file by putting nothing in it and
then add in that first log entry saying
| | 06:07 | that the logs were cleared and finally,
I said redirect_to. You will see when
| | 06:11 | that in just a second we try this out,
it will redirect to the same page that
| | 06:15 | the URL wont have "clear=true" anymore in it.
| | 06:18 | We will see that in action, let's
take a look. So I'll go and open up a new
| | 06:21 | Firefox window and we'll go to localhost
/photo_gallery/public and then where I
| | 06:26 | want to go is actually in to admin/login
.php and we'll try that out. I'm going
| | 06:32 | to login as kskoglund with secretpwd.
That was my password, secretpwd. Now I'm
| | 06:41 | logged in, it should have logged that.
Let's take a look at our log file, View
| | 06:45 | Log File and sure enough here we are,
we have got some old logs there, we have
| | 06:49 | got the new entry that I just created
and if I click Create log file, it then
| | 06:53 | clears up the logs and we start over again.
| | 06:55 | Now I wanted to show you what I mean
by that last redirect here. Let's take
| | 06:59 | that out for a second and let's just
reload the page Log file, okay and let's
| | 07:05 | clear the log file.
| | 07:06 | Now because I didn't redirect, notice
here that "clear=true". That might cause
| | 07:12 | us to inadvertently clear the log file
again. So by redirecting instead, I make
| | 07:17 | sure that I clear out that parameter
that was sent so that now, once we have
| | 07:22 | cleared it, it's gone and it has to
actually click the link in order to get
| | 07:26 | that clearing effect again. So while
that wasn't part of the assignment, that
| | 07:29 | is just a good practice to be in, to
keep track of what is up in that URL
| | 07:33 | string because that is something that
the User could reload the page, they
| | 07:37 | could bookmark it, so if you don't
want something sort of dangerous or
| | 07:41 | destructive up in there, you want to
make sure that you don't leave it up in there.
| | 07:44 | So hopefully, you got the same results
and you got it working, if not go back,
| | 07:47 | rewind the movie, see what I did, try
it on your own till you get it right.
| | 07:51 | When you are ready, I'll meet you in
the next chapter, where we'll talk about
| | 07:53 | uploading files via a web form.
| | Collapse this transcript |
|
|
8. Uploading FilesConfiguring PHP for file uploads| 00:00 | So far in our discussion of files and
directories, we have seen how to work
| | 00:04 | with files and directories that are on
the web server already. What we haven't
| | 00:07 | seen is how we can upload files from a
client's web browser to our web server.
| | 00:12 | Keep in mind, when we're developing,
they are on the same place but when we're done,
| | 00:16 | we may actually deploy our
photo gallery application to a web hosting
| | 00:20 | service that might be in Kansas City.
Meanwhile, we might be in San Francisco
| | 00:25 | or Miami and be uploading files to that
server using a web interface and that's
| | 00:30 | what we want to learn how to do in this
chapter is how to upload files to PHP.
| | 00:34 | Before we can do that though, we
need to take a look at how we need to
| | 00:37 | configure PHP so that it's able to do
file uploads. In php.ini, there are a
| | 00:42 | number of different options that we
can set and configure. Probably,
| | 00:46 | by default, all of these are going to be
set correctly on your machine, but every
| | 00:50 | distribution is different, so you want
to bring up php.ini or take a look at
| | 00:54 | php.info, remember how we did that
script, we'll look at that in a second and
| | 00:58 | you will want to examine these options
and make sure they are set to the right thing.
| | 01:02 | The first and the most important,
which is file_uploads turned On. It's
| | 01:06 | possible to turn it Off so that PHP
won't accept file uploads, so it should
| | 01:10 | have to be On or possibly it's true or
1, those all accomplish the same thing
| | 01:14 | and then upload_tmp_dir is where we're
going to upload files temporarily. We
| | 01:20 | just need a place where we can put them
when they are being uploaded and we can
| | 01:23 | grab them out of there and work with
them afterwards. So that's going to be the
| | 01:26 | temp directory. Null is the default or
it might just be simply not defined at
| | 01:30 | all on your machine, in which case it
will use the system's temp directory and
| | 01:35 | in most cases that's fine as long as
you have access to that, as long as the
| | 01:38 | web server has access to it, as long as
it has read and write abilities that we
| | 01:42 | have talked about before, otherwise
you can assign a different upload_tmp_dir
| | 01:46 | and then the remaining five options
all have to do with the size of the file
| | 01:50 | that you are going to allowed to be
uploaded and how long you are going to let
| | 01:53 | PHP spend trying to actually accomplish
that task, how long it's going to wait
| | 01:58 | to get that file and
receive it over the internet.
| | 02:00 | So on a slow connection, you might
need a little bit more time. So typically
| | 02:04 | these options work pretty well. The
maximum size for any post-request is 8M.
| | 02:10 | The upload_max_filesize is set by
default at 2M. Now you can change those and
| | 02:15 | configure them and make it 3, 4,
whatever you want, but by default, that's the
| | 02:19 | maximum size.
| | 02:20 | If you are trying to upload a 3M file
and it's not working and you are beating
| | 02:24 | your head against the wall going, wait
a minute, my PHP has got to be right.
| | 02:27 | Well, it may be that you never set
this upload max file size to allow files
| | 02:31 | that large to be received. So you want
to take a look at that and just know at
| | 02:35 | least what's there. Even if you don't
change it, you want to know how you have
| | 02:38 | it configured. And then the
execution time is how long it should spend
| | 02:42 | executing. Input time is how long it
will spend processing, which is slightly
| | 02:46 | different. By default it's set to no
limit and that's so the recommended thing.
| | 02:50 | Then memory_limit, how much memory is
each script allowed to use and 128M is
| | 02:56 | probably the default. You can up it if
you find that you need more memory. So
| | 02:59 | even though these are all probably
configured correctly for you already, it's
| | 03:03 | worth knowing what they are and more
importantly, it's worth knowing where
| | 03:07 | they are and that they may need changing in
case you have to troubleshoot your PHP uploads.
| | 03:12 | Let's take a look at the pho.info file
just to see some of these settings. So,
| | 03:17 | here I'm in my btb_sandbox. We have
created this file earlier, my_phpinfo.
| | 03:21 | That will just run that php_info function
and allows us to see everything that's
| | 03:26 | setup and if we just do a couple
of finds here, I'll just do find for
| | 03:31 | file_upload and here it is file_uploads
is set to On for me. I can do another one.
| | 03:37 | Let's do upload_temp_dir, no value,
so that means it's going to use the
| | 03:44 | default directory. That's the same as
being Null. Then let's say post_max_size.
| | 03:50 | There we are. You see that 8M and you
can keep going through all of them and
| | 03:55 | just take a look, see what they are
all set to. Mine are all set to those
| | 03:58 | defaults. If yours aren't, you can
try it with what you have got or you can
| | 04:02 | adjust yours accordingly, but those are
sort of the key parameters we need to work with.
| | 04:06 | Now the last bit of housekeeping I
want us to do before we actually start
| | 04:09 | diving into the PHP code is to create
the Upload folder where we're going to
| | 04:13 | input all of these files that we're
uploading and we're going to move back to
| | 04:16 | our btb_sandbox, so that's where we
are. We're in btb_sandbox, not in the
| | 04:19 | photo_gallery and we're going to create
an upload here and then we'll learn how
| | 04:23 | to apply it to our photo_gallery,
just like we have been doing.
| | 04:26 | So the first thing we're going to need
is a new directory here, you can create
| | 04:29 | the directory however you like, I'll
just go to the File menu and I'll click
| | 04:33 | New Folder for me and we're going to
call it uploads and that's where we're
| | 04:40 | going to do our uploads to.
| | 04:42 | Now of course, we know from working
with files already that the important thing
| | 04:46 | here is that we navigate into that
directory, btb_sandbox and we take a look
| | 04:54 | ls-la and we take a look at uploads to
see who owns it and what permissions do
| | 05:00 | they have. Well, right now I own it,
so we're going to need to also do sudo
| | 05:04 | chown and then whatever your web server
is, mine is www.uploads and it's going
| | 05:11 | to want my password. I can remember it
on here. There we are. And if you really
| | 05:15 | want to open that up to everyone,
remember that we can do Chmod and we can do
| | 05:20 | 777 uploads and that will then change
it so that everyone has the ability to
| | 05:27 | read and write into that folder.
| | 05:28 | Now that may not be a good thing on a
web server, but since this is a temporary
| | 05:31 | directory we're just playing around,
that's perfectly fine. So make sure that
| | 05:35 | you have read and write access into
that directory and then in the next movie,
| | 05:38 | we'll start seeing how to
send files as form data.
| | Collapse this transcript |
| Sending files as form data| 00:00 | Now that we know what are the trouble
spots in configuring PHP and we have a
| | 00:03 | directory for our file uploads, we're
ready to actually put those on to an HTML form
| | 00:07 | or in other words, how to send the file
as part of the form data, our post request.
| | 00:13 | So to get us started, I'm actually
going to jump up here to the basic.html that
| | 00:17 | we created a long time ago and I'm just
going to make it File > Save As and that
| | 00:23 | will give us some HTML to start with.
I'm going to call it upload.php and
| | 00:27 | I'll save it in the btb_sandbox
and then let's just call it Upload.
| | 00:31 | Now you are familiar with basic HTML
web forms. This will be an example of a
| | 00:35 | very simple web form that would be a
post request. It would post back to
| | 00:39 | itself, upload.php. It would send some
variables in the inputs as well as the
| | 00:45 | Submit button and then what we would
typically do is up at the top, we would
| | 00:49 | have some PHP that would actually do
the form processing before it got to the form.
| | 00:54 | So now what I'm going to show you is
how we can modify that so that it will
| | 00:56 | work with file uploading. Now the first
important thing that we need to add is
| | 01:02 | enctype="multipart/form-data", so that
lets it know that that's what it's going
| | 01:12 | to be sending as multipart form-data.
Essentially, it says there will not only
| | 01:17 | be text here, there may be files also.
That's what that's telling it.
| | 01:22 | It's an essential part of HTML, not PHP.
HTML that we put that in whenever we're going
| | 01:27 | to send a file in our post-request.
Then the second thing is the input type
| | 01:32 | that we use for files is file and then
the name of the file, which I'll call
| | 01:37 | file_upload, that's going to give us a
nice button that will let us select the
| | 01:41 | file that we would like to upload.
| | 01:42 | Now that's all just HTML, there is no
PHP there. Let's go ahead and just save
| | 01:46 | that real quick and let's open up a
web browser and instead of being in the
| | 01:51 | photo_gallery, let me just back up here
and go to the sandbox to upload.php.
| | 02:00 | So here we are. It's just a real simple
web form and you will see when I click in it,
| | 02:03 | it says okay, you are ready to upload.
Browse, it let's me browse and then
| | 02:08 | Upload is the button that will actually
let me upload that file. So that's what
| | 02:12 | we have got in our HTML.
| | 02:13 | So the most important part there is
just that we have this ink type file
| | 02:17 | form-data and then we us type-file.
There is one other important thing that
| | 02:21 | we 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:35 | for how large the maximum file size can be.
| | 02:38 | Now I'm going to go ahead and just
paste in a comment here in PHP that will
| | 02:42 | give you a reminder. Let's take a look
at that. I need to just move this over a bit,
| | 02:47 | there we are. The maximum file
size in bytes must be declared before that
| | 02:51 | file input field and it can't
be larger than the setting in our
| | 02:55 | upload_max_filesize that's in php.ini.
So we don't want to go any larger than that.
| | 03:00 | That's going to always be
the ultimate authority for what the
| | 03:03 | maximum_filesize_php will allow.
It's going to be what's in that file.
| | 03:07 | Now, this form value can be manipulated and
you should still use it, it's a good practice,
| | 03:11 | but you are going to rely on
that upload_max_filesize to make sure
| | 03:15 | that nothing larger than that ever
comes through, but what we're saying is
| | 03:19 | for this form, this is the maximum. Now
someone can hack that, so it's not 100%
| | 03:24 | reliable, but you can think of it as a
polite declaration, a way of saying to PHP,
| | 03:28 | here comes the file that is less than
this size and if it turns out that's not true,
| | 03:32 | PHP will stop and complain.
| | 03:35 | So it's a nice way of saying, hey PHP,
someone gave you a file and here is what
| | 03:39 | to expect. Now I went ahead and just
put in 10000000 here as the value, so
| | 03:43 | 10000000 bytes would be roughly 1M.
Now that's not exactly 1M, if precision
| | 03:48 | matters, you could put in the actual
value there and that's really all there is
| | 03:52 | to making this work with PHP. That's all
there is for us to be able to upload a file
| | 03:56 | and the very last thing that I'll
do here is just to put in a little PHP
| | 04:00 | that will allow us to pass some
messages from the form processing that will be
| | 04:04 | up here at the top, down to the bottom
so that we can say, hey, your file was
| | 04:08 | uploaded successfully or
hey, there was a problem.
| | 04:10 | We will go ahead and take care of that
now so that we can pass those messages.
| | 04:14 | Now in the next movie, we'll take a
look at how we can inspect the file that
| | 04:17 | gets 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:00 | Now that we have a web form that can
submit files for uploading, we now need to
| | 00:04 | learn how to process those files
and the first step is going to be to
| | 00:07 | understand what's being submitted and
to inspect the uploaded files that comes across.
| | 00:13 | In order to do that, we're going to
need to look at another super global.
| | 00:16 | We looked at a bunch of them already.
We saw Get, Post, Cookie, Session and
| | 00:19 | Server, but there is one more which
is called Files, and Files is going to
| | 00:23 | contain any uploaded files
submitted with the Post Request.
| | 00:27 | So it's not going to be found in the
Post super global. Files will get split
| | 00:30 | off and they will get pushed into the
File super global separately. All of our
| | 00:34 | other Post variables will still be
in Post. Just Files will be in Files.
| | 00:39 | The way we're going to access those is
to say, well, what is the name of that
| | 00:42 | form input field? In our case, it was
file_upload and $_FILES, and then in
| | 00:47 | square brackets, and then the name of
the field that was submitted will give us
| | 00:52 | back an associative array and that
array is going to contain five pieces of data.
| | 00:56 | It's going to have the name of the file,
its original file name on the user's machine.
| | 01:01 | It's going to have the type
of file that it was, the mime type that
| | 01:04 | get sent when it's sent by the browser,
the size and bytes of the file,
| | 01:08 | the temporary name where the file was stored
on the server, and the error code that goes with it.
| | 01:13 | We'll take a look at errors in the next
movie, for now let's focus on the other four.
| | 01:16 | The example at the bottom that
will show the syntax of how we're going to
| | 01:19 | pull back a single one of those items.
file_upload name would then be the
| | 01:24 | original file name, and we can make
use of that. We can change it or we can
| | 01:27 | keep the same name, it's up to us.
But that's where we'll get that value.
| | 01:31 | One great way for you to see this
array and what it looks like is to just try
| | 01:35 | it out. So we have our form for our
form processing. Instead of actually doing
| | 01:39 | any real form processing at this
point, let's just output something.
| | 01:43 | We are just going to put in pre tags.
That's going to basically respect the
| | 01:46 | white space formatting, the HTML
thing and even though we're not inside the
| | 01:50 | HTML, we could drop this down here
inside the body. For now, we're just going
| | 01:53 | to put it up here at the top. It's not
perfectly valid HTML but that's okay.
| | 01:57 | Pre tags, print_r, which will print
out the array for us, it's there and then
| | 02:03 | file_upload, and then we'll put an hr
tag at the end. So let's just try this
| | 02:07 | out and see what we get back.
| | 02:09 | So if I open up Firefox, here I'm with
upload.php. I'll just reload the page.
| | 02:14 | You will see I get my hr tag, Browse,
and I'll just go into btb_sandbox for now
| | 02:19 | and I'll go and just find filetest.txt.
That was the file we were practising,
| | 02:26 | writing to earlier. I'm going to send
that. And you will see I put the whole
| | 02:30 | path here, for where that file is
located. And when I click Upload, it's going
| | 02:34 | to send that file right away.
| | 02:36 | Now notice here it's not an image file.
This is not unique to sending images.
| | 02:40 | It's any kind of file we want. It
can be a text file, Excel file, Word
| | 02:44 | document, any file gets sent the same way.
| | 02:47 | So where we click Upload and look what
we get back. We get the same form again
| | 02:51 | but our output at the top says
here is the contents of that array.
| | 02:55 | The file name is filetest.txt. No path
or anything, just the file name.
| | 03:00 | The type, text/plain.
| | 03:02 | If it had been an image, it might have
said that it was a JPEG, for example.
| | 03:06 | The tmp_name, this is where the file is
stored. Notice that that's a full path.
| | 03:10 | For 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:18 | But notice that the name of the file
is something crazy that it came up with,
| | 03:22 | phpWH6foz. That's where the file is on
my server. I need to get that tmp_name,
| | 03:28 | if I want to look at that file, if I
want to move that file, or do anything
| | 03:32 | with it. I'm going to need to reference
that item in the array to find out the
| | 03:35 | name of the file. The error you will
see is zero, which means that there were
| | 03:38 | no errors, and the size of the file is
14 bytes. That's all there is to it. So
| | 03:43 | this demonstrates to you
what that array looks like.
| | 03:46 | Now in the next movie, we'll take a
little bit of a closer look at some of the
| | 03:48 | possible upload errors that you could
come across, before we look at moving the
| | 03:53 | uploaded files and working with those.
| | Collapse this transcript |
| Uploading errors| 00:00 | Now in the last movie, we saw how
that one of the values inside that file's
| | 00:04 | super global array is the error code
that gets returned. In this movie, I want
| | 00:08 | to take a little closer look at the
possible error codes you can get back and
| | 00:11 | talk about how to handle them effectively.
| | 00:13 | First, let's look at the list. There
are eight possible errors that we can get back.
| | 00:17 | Now the first is not actually an
error. It's error 0. It means that there
| | 00:20 | were no errors. So in that case, there
is actually seven. If we take a look at
| | 00:24 | each one of those, in the first column,
we have the name of the error, and
| | 00:27 | in the second column,
we have the number of the error.
| | 00:30 | That's not really a name. The first one
is actually a constant. It's a constant
| | 00:34 | in all capitals that's equal to the
value of the number. So we can use either
| | 00:39 | one for checking. We can say if we get
back Upload_err_ok, or if we get back 0,
| | 00:44 | then take this action. So both of them
will work for us. I find it's a little
| | 00:47 | easier to work with the named ones
than it is the numbers, but if you find
| | 00:51 | that's easier for you the
other way around, that's fine.
| | 00:53 | Then the third column there explains
what each of the errors are. So you have
| | 00:57 | seen the first one. The second one,
the ini_size error means that the upload
| | 01:01 | was larger than what was specified in
the PHP INI file. So we could either
| | 01:06 | increase that or we could return an error
saying, hey! Sorry, that file is too large.
| | 01:10 | Now error number 2 says that the form
size was too large, which means that that
| | 01:16 | max_filesize value we sent, it went
over that number. So we get the ability to
| | 01:20 | check for both. Did it go over our max_
filesize and did it go over the PHP size?
| | 01:27 | Error number 3 is that there was a
partial upload. The file didn't finish.
| | 01:31 | Error 4 would be that no file was
sent at all. You will notice that error
| | 01:35 | number 5 is missing from the sequence.
That's an old error. That's gone now.
| | 01:39 | Error number 6 though is that there is
no temporary directory and number 7 is
| | 01:44 | that we can't write to the disk.
There is a read/write problem, permissions
| | 01:47 | problem probably.
| | 01:49 | The last one is a little obscure but
it says that there is some kind of an
| | 01:51 | extension that's stopping the file
upload. So we would know to troubleshoot
| | 01:55 | then our extensions, which is
something we haven't talked about yet. You can
| | 01:58 | also always get a full list of these on
the PHP website, and I put the URL down
| | 02:02 | there where you can look those up.
| | 02:03 | But what I want to move on to show you
now is how we can effectively handle the
| | 02:07 | errors and give the user some nice
messages back. Essentially, what we want to
| | 02:11 | do is convert the results we get from
either column 1 or column 2 into column 3
| | 02:16 | that we can return as a
nice message to the user.
| | 02:19 | So I found that the best way to do
that is to define an array, which is just
| | 02:23 | going to be called upload_errors, and
its associative array that contains those
| | 02:28 | names that we just saw with a message.
Then we have the ability to look up the
| | 02:32 | error and output the message, find the
key, return the value. Note, then it'll
| | 02:37 | allows me to give
something nice back to the user.
| | 02:40 | We can try that even now without
having done anything else by just simply
| | 02:44 | finding that error inside file_upload
error, and then using that as the key or
| | 02:50 | the index for where we would find the
message that it should return. We have
| | 02:54 | already setup message down here, so it
would return the message. Let's try it.
| | 02:58 | So I'm just going to bring up Firefox
and here I'm with upload.php. I'm going
| | 03:04 | to browse again to that same file we
did before, filetest.txt. You can put
| | 03:09 | anything you want at all, it doesn't
matter, and then say Upload. So here we
| | 03:14 | are, you will see the error it gave
was 0 and it came back and returned
| | 03:18 | "No errors" to us.
| | 03:19 | Now let's just try this time without
browsing for anything at all, or
| | 03:22 | I'll leave it blank and just hit Upload.
You see it came back with error 4 and
| | 03:27 | the error was "No file". Now we can also
try uploading files that we know were too
| | 03:31 | large or setting some of those maximum
values lower, just to see if we can try
| | 03:35 | and get back all those errors, but
I don't think it's really necessary.
| | 03:37 | We know that it's working now, we know
that that feature is working and that's
| | 03:40 | why I want to show you is that here is
a way to gracefully handle those errors
| | 03:44 | that we give back to the user.
| | 03:46 | Now we have a better understanding of
the error codes. In the next movie, let's
| | 03:49 | go back to looking at how we can work
with those uploaded files, specifically,
| | 03:52 | how we can move them out of the
temporary directory into whatever directory
| | 03:56 | we want to work with them and keep them in.
| | Collapse this transcript |
| Moving uploaded files| 00:00 | A few movies back, we talked about how
to upload files via a web form, I noted
| | 00:04 | that the moment that you hit Submit,
it sends the file to the web server, and
| | 00:07 | at that point the file has been
transferred, it's on the web server. It's just
| | 00:12 | sitting in a temporary directory,
waiting for us to do something with it.
| | 00:15 | Now we can read that file where it is,
we can write to it, we can delete it.
| | 00:20 | It's a perfectly legitimate file
just sitting in the temporary directory.
| | 00:24 | Chances are we don't want to do
those things. Chances are we want to move
| | 00:28 | that file out of the temporary directory,
give it a name that we like, and
| | 00:31 | put it someplace more permanent. After
all, the temporary directory could get
| | 00:34 | overwritten; the system could wipe out
those files periodically if it wants to.
| | 00:38 | That's why it's called a temp directory.
| | 00:40 | So in this movie, we're going to see
how to move those files into our uploads folder.
| | 00:44 | So I'm back in upload.php, and
I'm just going to take out the pretext,
| | 00:48 | where we're inspecting those values.
We don't need to inspect those anymore.
| | 00:52 | I am just going to put in some basic
skeleton for our form processing. We have
| | 00:56 | seen this kind of thing before. But
we're only doing a single page submission,
| | 00:59 | and the form submits to itself. We're
going to check and see, was the post
| | 01:03 | variable submitted. If it was, then
we'll want to process the form data, in
| | 01:07 | this case, move the file over. We'll
be using this error, but not just yet.
| | 01:12 | If we're going to move the file, the
first thing we need to know is what file
| | 01:16 | do we need to move. So, that's going
to be the temporary file, and we saw how
| | 01:19 | to do that by using temp name before.
| | 01:21 | The second thing we want to come up
with though is that location of where we
| | 01:25 | want to put the file. So the name
of the file can be anything we want.
| | 01:28 | You could name it, 0123abc.jpg, or you
could go to a database, and look at what
| | 01:35 | the next value is ought to be or something.
It could be based on the user's name,
| | 01:38 | maybe this is user K. Skoglund's
headshot, and so we could call it,
| | 01:42 | kskoglund_headshot. It's your chance
to name it whatever you want, but we do
| | 01:46 | have access to what it was named
originally on the user's computer. So in this
| | 01:51 | case I'm going to use that same name.
We're not going to change the name;
| | 01:54 | we're going to keep the name that they had.
| | 01:56 | But because I'm keeping their name,
I'm going to run it through a function
| | 01:59 | called, basename. basename is going to
make sure that we get just the name of
| | 02:03 | the file that's at the end. So that's
going to be, for example, picture.jpg. It
| | 02:08 | will be the name of the file dot extension.
| | 02:10 | What it's also going to do is help
ensure that our system doesn't get hacked by
| | 02:14 | someone putting in something that's a
little bit crazy for a name of a file
| | 02:18 | that might interact with our file
system in a bad way. It's going to help sort
| | 02:21 | of purify it for us or escape it. So
basename is going to be good for that, and
| | 02:26 | that will give us then the target file.
Then I'm going to go ahead and say
| | 02:29 | well, the upload directory where we want
to put these is going to be in uploads.
| | 02:33 | Now there could be a plenty of sort of
preprocessing of taking a look at those
| | 02:36 | values that were there. You could
check to see if the file exists first, to
| | 02:39 | make sure that you are not going to
accidentally try to override it or
| | 02:42 | something like that. You also could
stop and do checking here to see whether or
| | 02:46 | not there were actually any
errors in the form as well.
| | 02:49 | I am not going to any of that. Instead,
I'm going to move directly to taking a
| | 02:52 | look at what we need to move this file.
That is going to be move_uploaded_file.
| | 02:59 | That's the PHP function that will move
the file. It only moves files that have
| | 03:04 | been uploaded, files that are sitting
in that temporary directory, and it knows
| | 03:08 | because it's there, that it's
an uploaded file. That can tell.
| | 03:11 | So what we wanted to say is move the
uploaded file, with this name, $tmp_file,
| | 03:18 | and 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:28 | That's something that is in our other
application. So we'll just use the /.
| | 03:32 | So $upload_dir."/".$target_file.
That's where it should go to.
| | 03:37 | So that's what we want to do; we want to move
the file there. Now that will do it on its own.
| | 03:41 | That PHP function will attempt to move the file.
| | 03:44 | But let me make a note here, which
is that move_uploaded_file will return
| | 03:48 | false, if the file is not a valid
upload file or if it cannot be removed for
| | 03:53 | any other reason. Well, since it
returns false, there is a great reason that we
| | 03:56 | can put if around it. So if we were
able to move the file, then do one thing,
| | 04:04 | else, do something else. Let's grab
this because we know that the else we would
| | 04:09 | want to do if something goes wrong is
display an error there. And if not, let's
| | 04:14 | put in a simple $message = "
File uploaded successfully".
| | 04:22 | So we wrap it in an if-else statement,
but ultimately what we're doing is
| | 04:25 | saying, were we able to move the
uploaded file from its temporary place to the
| | 04:31 | target place, where we wanted, with
the name that we've given it. That's all
| | 04:35 | there to it. That's absolutely all
there is to moving files after they have
| | 04:40 | been uploaded.
| | 04:40 | Let's go ahead and try it out. I'll
save this. Let's get our directory here
| | 04:44 | where we can see it. Here is uploads,
and uploads right now has nothing in it.
| | 04:49 | We did make sure earlier that it was
writable. So now we would just need to go
| | 04:52 | to Firefox and let's upload a file. So
Browse, and we'll take that same file
| | 04:57 | again, you could put a different one
if you want, filetest.txt, and open it.
| | 05:03 | Then Upload, "File uploaded
successfully". Let's take a look over here, and
| | 05:07 | sure enough, here it is.
| | 05:09 | Now it's uploading it to a directory
on the same server, but this could be on
| | 05:13 | two separate servers, so that this is
on a local copy, let's say in Chicago,
| | 05:18 | and this one is on another copy that's
in Dallas, and it's uploading it to that
| | 05:21 | directory. Don't be fooled by the fact
that these are in the same place. It's
| | 05:25 | because we're running both our web
browser and the web server in the same place.
| | 05:29 | That's really all there is to
uploading files, once you understand those
| | 05:32 | configuration options, you make a few
changes to your form, then it's simply a
| | 05:36 | matter of pulling values out of the
super globals and using move_uploaded_file
| | 05:40 | to put the new file in the right place.
| | 05:42 | I think that you now have a very
good understanding of how files and
| | 05:45 | directories work in PHP, and you
should feel very comfortable by now.
| | 05:48 | We're ready to move back to the Photo
Gallery and finish flushing out that application.
| | Collapse this transcript |
|
|
9. Completing the User ClassRemaining user CRUD| 00:00 | In the last few chapters we have been
working with and uploading files. Once
| | 00:03 | you know how to work with databases,
objects and these uploaded files, then the
| | 00:07 | next few chapters should be pretty
straightforward. Essentially, we would just
| | 00:10 | be pulling together all of these
concepts. But before we can start uploading
| | 00:13 | files to new photograph class, we need to
add a few more object oriented methods first.
| | 00:17 | We will start by adding these methods
to our existing user class. This should
| | 00:20 | be a very straightforward usage example.
Then we can apply those concepts to
| | 00:24 | our photograph class after that. Now
earlier we created the ability to log in
| | 00:29 | and log out by finding users in our
database. But we skipped over the part
| | 00:32 | about creating, updating and deleting
users. The other parts of CRUD, Create,
| | 00:37 | Read, Update and Delete. So
let's add those methods now.
| | 00:40 | So we're going to be switching from the
btb_sandbox back to the photo_gallery.
| | 00:43 | So open up that photo_gallery directory
again, and we're going to be working on
| | 00:46 | user.php to begin with. So I'm going
to open that up. Now if you remember, we
| | 00:51 | had gone through and created some
authentication methods, as well as some
| | 00:55 | common database methods. We talked
about why we wouldn't be able to move those
| | 00:58 | up to database objects, until we have
the ability to do Late Static Bindings,
| | 01:02 | but for now we have these
static methods that we have created.
| | 01:05 | Well, right below this, we're going to
create a few new ones and they are going
| | 01:09 | to be, create, update and delete.
Notice that these aren't Static methods.
| | 01:13 | These are Public Instance methods.
If you think back, our Find methods,
| | 01:17 | find_all, find_by_id, find_by_sql or
Static methods, because we want to be able
| | 01:21 | to call them from the Class level. They
returned instances, but we didn't have
| | 01:25 | an instance to begin with.
| | 01:26 | Unlike our Find method, these three
methods will all require that we have an
| | 01:29 | instance of an object to begin with. We
want to add or update its attributes in
| | 01:33 | the database or delete its database
entry altogether. In each of those cases
| | 01:37 | though, we're going to have an object
to start with, an object that we want to
| | 01:41 | save to the database or an object
that we want to update in the database.
| | 01:45 | Now just like those Static methods we
created earlier, we might eventually want
| | 01:49 | to promote these to the database
object class, keeping in mind any problems
| | 01:53 | with early Static Binding. But we'll
start out by creating them in the user
| | 01:56 | class. I think it will be
easier to work within there.
| | 01:59 | So let's start up by focusing on coding
the Create method, and we'll do that in
| | 02:02 | the next movie.
| | Collapse this transcript |
| Creating users| 00:00 | In order to complete the user CRUD,
we're going to start out by writing the
| | 00:03 | create method, in order to
allow us to create users.
| | 00:06 | Now the first thing I want to point
out to you is that this is different from
| | 00:09 | simply instantiating a new user. With
that, we did something like $user = new
| | 00:14 | User. What we're talking about now
is writing a method that will take that
| | 00:18 | instance, and allow it to be saved to
the database. So we can attach attributes
| | 00:22 | to it, the first_name, the last_name,
the username, the password, and then
| | 00:26 | we can tell it, all right, save that to
the database. We'll do that using a method
| | 00:31 | that we'll call create.
| | 00:32 | Now because we're going to be working
with the database, the very first thing
| | 00:35 | we're going to want to do is use
global to bring in database. That is the
| | 00:41 | variable that we had already defined
that has an instance of our database
| | 00:45 | object. So then we can use it
to run queries, for example.
| | 00:47 | Now I'm going to post in some comments
here, just to remind you that we don't
| | 00:51 | want to forget our SQL syntax, and our
good SQL habits. So I have gone ahead
| | 00:56 | and just reminded you sort of what the
basic structure of a insert statement
| | 01:00 | ought to look like, and then made a
couple of notes about our good habits that
| | 01:03 | we're going to put single quotes
around all the values, and we're going to
| | 01:06 | escape all the values, to prevent SQL Injection.
| | 01:10 | Now keeping those points in mind,
we're ready to actually write the SQL. Now
| | 01:13 | I'm going to go ahead and just paste it
in here and let you take a look. We're
| | 01:16 | going to insert into the table users,
and right now I'm going to go ahead and
| | 01:20 | just say users. I'm not going to try
and find that dynamically, even though if
| | 01:24 | you remember up here at the top,
we defined that as table name. For now,
| | 01:28 | we're just going to go ahead and put it in
and hard code it. We can abstract it later
| | 01:32 | and we'll do that.
| | 01:33 | Then I have got the field names, so we
have got username, password, first_name
| | 01:36 | and last_name. Those are the fields
that we're going to try and update. I left
| | 01:40 | ID out of there, because ID will
autoupdate on its own, because we have set it
| | 01:44 | to auto increment when we created the database.
So I don't need to send a value for that.
| | 01:48 | Then I have got VALUES, and then notice
I've got a single quote here, followed
| | 01:52 | by the first value, which is going to
be username, and I'm using escape value,
| | 01:56 | that method we wrote in the database
class. That will escape things so that
| | 02:00 | they are safe from MySQL Injection.
Then I have got a single quote, comma,
| | 02:05 | space, and then another single quote.
| | 02:07 | Now from this single quote down to this
single quote is one value. I have just
| | 02:12 | put the single quote up on the line
before it, don't let that pull you or throw
| | 02:15 | you off. You need to be careful and
make sure that you have all these pairings
| | 02:18 | of single quotes correct. Then I have
got commas between all of them and then
| | 02:22 | I have got the last one here, comma,
and then close the parenthesis on VALUES.
| | 02:27 | So be very careful about your SQL
syntax, make sure that you have got it all
| | 02:31 | right. But when we're done, then we're
simply ready to run our query statement.
| | 02:36 | Running this SQL query is very simple,
because we coded our database class and
| | 02:41 | we have a method called query. So we
simply say run this query. If it returns
| | 02:45 | true, then return true, if not, then it
returned false. That will let us know,
| | 02:50 | whether it happened or not.
| | 02:51 | Now there is one additional thing that
we need to take care of with an insert
| | 02:55 | statement. This is a very important
step. We want to also update the id
| | 03:00 | attributes of the object to be
whatever the database just saved that as. We
| | 03:04 | don't know what that is because it was
auto incrementing, and there could be
| | 03:07 | several insert statements happening
from different users at the same time.
| | 03:11 | So we want to tell the database class
to use its insert_id method to give us
| | 03:15 | that id value and then we'll put it in
this object. So now, we already have the
| | 03:20 | username, the password, the first name,
and the last name stored. Now we also
| | 03:24 | have the id. So this is all there is to it.
| | 03:26 | Now we have coded a create action
that will take whatever the current
| | 03:30 | parameters are in this object and will
add them to the database. So let's test
| | 03:34 | this out. I'm going to close up that
file, and let's go into, public, admin,
| | 03:39 | and then I'm going to take the
index.php action. I'm just going to do
| | 03:43 | File>Duplicate on it. I'll have copy,
and I'm just going to call it, test, and
| | 03:47 | this is where I'm just going to do some testing.
| | 03:49 | I'm going to open this up, and I'll
go ahead and leave all the header and
| | 03:53 | everything in there. I'm just going to
take out the HTML that we had. This will
| | 03:56 | initialize it. It will make sure
we're logged in. So testing our new create
| | 04:00 | method is going to be easy. We just
simply instantiate a new user, and then
| | 04:04 | give it all of the attributes that we
want, and then tell it create. Now we
| | 04:09 | could make this last line into an if-
then statement that would perform one set
| | 04:14 | of actions if it created or not
successfully. But I'm just going to actually
| | 04:17 | look in the database to
see if it got created or not.
| | 04:20 | So before we test this out, I'm just
going to open up my phpMyAdmin that I have,
| | 04:25 | so that I can see what's in the
database. It will just make it nice and
| | 04:27 | easy to see when these records get added.
So you can see I have already got the
| | 04:31 | user that I created earlier.
Refreshing it just shows that same user.
| | 04:35 | Now what I want to do is use that test
page. I'll create a new window here and
| | 04:39 | we'll go to, photo_gallery/public/admin
/test.php. I'll need to log in first,
| | 04:50 | secretpwd, all right, now let's go
that test page, test.php, all right. Now,
| | 04:58 | I don't see anything on the page, but
that's because I didn't actually echo
| | 05:01 | anything back. It should have still
made its entry in the database, and
| | 05:05 | you will see there it is. johnsmith
with the password that I gave it.
| | 05:08 | Now if you have written that create
statement, then you should get the same
| | 05:11 | result, if not, you want to go back and
debug it till you get a similar result.
| | 05:15 | In the next movie, we'll see
how to code the update method.
| | Collapse this transcript |
| Updating users| 00:00 | In this movie, we'll work on coding
that update method inside our user class.
| | 00:04 | The idea here is that we have
already pulled an instance down from the
| | 00:08 | database. It already exists in the
database; we have now made an object
| | 00:11 | instance of it. We change a few
attributes on it and we want to save those
| | 00:15 | changes to the database. We're going to
write a method that will allow us to do that.
| | 00:19 | Now I'm going to set the test.php
aside for now and go back to user.php.
| | 00:24 | We'll use test again in a minute. I want
to focus on coding the update method. So,
| | 00:28 | just like before, I'm going to bring in
the database from the global scope so
| | 00:32 | that we can use that. Then I'm going to
just put a few notes here to remind you
| | 00:37 | what the SQL syntax should like and
then the good SQL habits we want to
| | 00:42 | make sure that we also keep.
| | 00:44 | Now the SQL that we're going to write
for this is going to look like this.
| | 00:47 | Let me just expand this so that it all
shows up nice and neat. We're going to
| | 00:51 | update the user's table. We're going
to set the key username=, here is a
| | 00:58 | single quote, the escaped value of
username from this object, the attribute
| | 01:03 | username, and then another single
quote. So the escape value will make sure
| | 01:06 | that we don't have any problems with
the SQL injection and then we have got
| | 01:10 | comma, space, and then the next value.
| | 01:13 | Notice that there is a space here
before the WHERE. The WHERE lets it know
| | 01:17 | where to locate the record that we
want to update, so we definitely need that
| | 01:22 | condition, telling it which one. And I
just want to make sure that there is a
| | 01:25 | space there. It doesn't matter whether you
put it before the WHERE, if you put it here,
| | 01:29 | but your SQL will be invalid
if you don't have a space between this
| | 01:33 | last single quote and the WHERE statement.
| | 01:35 | So, id=, and then we go ahead and
escape the value of id again. Now that's not
| | 01:40 | strictly necessary, because the id
probably was pulled from the database to
| | 01:44 | begin with, but it's a good practice.
It doesn't hurt just to make sure that
| | 01:49 | this somehow didn't get changed, so
we're go ahead and escape it one more time.
| | 01:53 | You could also choose to leave that step out.
| | 01:55 | Now once we have all our SQL constructed,
we're ready to run the database query.
| | 02:00 | And you remember from the
Essential Training that the way to know
| | 02:03 | whether this happened or not is not to
see whether it returns true, like we did
| | 02:07 | for the create action. Let's look at that.
If the database query returned true or not.
| | 02:12 | With update actions, what we
want to test is whether the affected_rows
| | 02:16 | is equal to 1. So if affected_rows equals 1,
then return true, otherwise return false.
| | 02:23 | That will be all that we need for our
update action. So I'll close that.
| | 02:27 | Now in order to test it out, I'll open up
test.php and I'll start by just commenting
| | 02:32 | all of this out, so that we won't
recreate the record and instead, we'll say
| | 02:36 | user= and we'll need to pull the user
out of the database. I'll do that using
| | 02:40 | a static method that we wrote earlier,
find_by_id, and the id that I want to find,
| | 02:46 | I can look in phpMyAdmin
and it's id number 2.
| | 02:51 | So find_by_id number 2. That will pull
it out of the database. Now let's make a
| | 02:55 | change to one of its attributes.
Let's say the password is now going to be
| | 02:59 | equal to, instead of abcd12345,
let's just reverse it so it's 12345abcd.
| | 03:09 | Then last of all, tell it, okay, now
that you have made that change, update.
| | 03:14 | Now we could again, put an if statement
here to test whether it happened or not.
| | 03:17 | We're actually going to look
directly into database, because we're not
| | 03:19 | interested in providing user-friendly
messages, as much as we're making sure
| | 03:23 | that our method is actually working.
So I'll save it. I'll go back and
| | 03:27 | we'll reload the test page. That's now
going to run my update code, not my create code.
| | 03:31 | Okay, now that it has run, let's take
a look and let's just refresh the database,
| | 03:36 | and sure enough,
it made the change, 12345abcd.
| | 03:41 | Now if you didn't get that result, you
want to go back and debug it. Make sure
| | 03:43 | that your SQL is right, until you get
the same result. Now I'm going to make
| | 03:47 | one more improvement here before we go
on, which is I'm going to open up user
| | 03:51 | again. I'll just collapse this down,
so that we see create and update.
| | 03:55 | Now I'm going to write another nice,
convenience function here, function save.
| | 04:03 | Now it would be great if we didn't
have to keep track of whether or not
| | 04:06 | the object was actually in the database
or not. We could just say save and figure
| | 04:10 | out whether or not it had
previously been saved or not.
| | 04:13 | So save would perform both; it would
either create it if it needed to be or
| | 04:17 | it would update it. It turns out that's
pretty easy to do because a new record
| | 04:22 | won't have an id. So if we have id
set already, then we know that it is a
| | 04:28 | record that's from the database. If id
has not been set, then we know that this
| | 04:32 | has not yet been saved in the database.
And so, we can have a simple function
| | 04:36 | called save that will choose whether
or not it should run the update method or
| | 04:40 | whether it should run the create method.
| | 04:42 | We can try it out and make sure that
it works using that test page again.
| | 04:44 | Let's just go back there real quick, test.php,
and this time let's change it to be,
| | 04:50 | wxyz for the password and instead of
update, we'll say save, and then let's go
| | 04:57 | back to Firefox. We'll reload our test
page and we'll check our code, refresh,
| | 05:04 | and it still works.
| | 05:05 | Now it not only will save make it a
little bit easier on us to write, because
| | 05:09 | we don't have to remember create
and update. We can just use save as the
| | 05:12 | single method, but it actually prevents
mistakes, because the way that we have
| | 05:16 | written the create method now,
we actually could create an object using an
| | 05:20 | instance and then we could say create
again and it would create it again.
| | 05:24 | It doesn't have any kind of mechanism
in there to make sure that this hasn't
| | 05:28 | already been created.
| | 05:29 | Now we could write one. We could say
well, if it has an id then don't create it,
| | 05:32 | but it's easier just to write one
here and let the object be smart
| | 05:36 | about which one it ought to perform.
Now probably to be safe, you would
| | 05:39 | actually probably want to make these,
instead of being public, you would want
| | 05:42 | to make them protected, so that you
actually could not call create and update
| | 05:47 | directly. You would have to use save;
you would force the user to use save.
| | 05:50 | But for now, I'll leave them public
and leave that choice up to you.
| | 05:53 | In the next movie, let's take a look
at how we can write the delete method.
| | Collapse this transcript |
| Deleting users| 00:00 | Now that we have seen how to create
and update users, we're going to want to
| | 00:03 | write the method for allowing us to
delete users. Once again we're going to
| | 00:06 | have an instance that we have already
pulled from the database, so it exists in
| | 00:09 | the database. It's been instantiated
and we're going to then have an instance
| | 00:13 | method called delete that
will delete it from the database.
| | 00:16 | Once you know how to do create and
update, I think you will find that delete is
| | 00:19 | very simple. Now just like before,
I'm going to open up user.php and what
| | 00:23 | we're going to be focused on is the
delete method, and just like we did last time,
| | 00:27 | we're going to call in from the global
scope, the database, so that we can use it.
| | 00:31 | I will put in my comment reminder about
some of those good SQL habits, and the
| | 00:36 | syntax for delete, delete from the
table where some condition is met.
| | 00:42 | Then LIMIT 1, it's always a good practice
if we only want to delete a single record
| | 00:47 | to go ahead and put this sort of
extra insurance in there. Now because
| | 00:50 | we're going to be using id for the condition,
there should only be one record with
| | 00:54 | that id. But it's still a good
practice to go ahead and use that LIMIT 1.
| | 00:58 | So the SQL, I'll go ahead and just
paste in so we can take a look at that.
| | 01:02 | It is just going to be simply "DELETE
FROM users", "WHERE id =", and then the id
| | 01:06 | of this current object, and make sure
you have a space again between all of
| | 01:10 | these different lines, make sure that
we have spacing, and then LIMIT 1.
| | 01:15 | Just like the update, the test of whether
the query worked is actually going to be
| | 01:19 | affected_rows to see whether
the rows affected was 1 or not.
| | 01:23 | So that's all there is to it. Let's
just save that and let's open up our
| | 01:26 | test.php again, and I'm going to
comment out the update that we did earlier,
| | 01:31 | and let's just do a new one. We'll go
ahead and find it again, there we go,
| | 01:37 | find user with the id 2. This time
though, we want to say user->delete, and
| | 01:45 | that should delete our
user, should be that simple.
| | 01:47 | So let's bring out phpMyAdmin, we'll
let's just refresh it to make sure that
| | 01:51 | we've still got johnsmith there, id
number 2. Then we'll open up our test page,
| | 01:58 | we'll run it, and now we come back and
we say Refresh, and he is gone. So the
| | 02:04 | user was deleted successfully.
| | 02:06 | Now 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:15 | make that clear to you. We're going to
create a new user called, johnsmith, and
| | 02:19 | then right afterwards, we're going to
delete it. Now it should probably be id
| | 02:23 | 3, this time I'm going to create a
new one. So we'll create it and then
| | 02:26 | immediately delete it, but I'm going
to do one other step, which is echo
| | 02:31 | $user->first_name.
| | 02:33 | Now notice that we have already done
the delete, we have deleted from the
| | 02:36 | database, it's gone, but we still have
the instance of our object around. So
| | 02:41 | let's go ahead and try this. Let's
open up our Firefox, save just one more
| | 02:46 | time, make sure he is still gone, and
test.php, we'll run it and it comes back
| | 02:51 | and still says John.
| | 02:53 | So even though we refresh it, and he is
not there in the database, it was still
| | 02:57 | able to pull up his first name,
because that instance of the class, the PHP
| | 03:03 | instance, still exists, even though we
have told SQL, hey, do a database delete
| | 03:08 | for us. Now, most times that's not a
big deal and in fact, sometimes it can be
| | 03:12 | really useful because we could say,
for example, that this was deleted.
| | 03:17 | So it can actually be a little bit
helpful to have the instantiation still
| | 03:21 | around where we have access to it, but
don't be fooled into thinking that, now
| | 03:24 | you could do, for example, an update
on it, because it doesn't exist in the
| | 03:27 | database anymore. So I just wanted
to make sure that that point is clear.
| | 03:31 | In the next movie, let's take a look
at how we can abstract what we have just
| | 03:34 | done in the user module, so that we
can apply it to other classes as well.
| | Collapse this transcript |
| Abstracting the database table name| 00:00 | We have now successfully coded the
Create, Update and Delete methods on our
| | 00:04 | user class. Ideally, what we would
like to have is these methods be abstract
| | 00:09 | enough that we would be able to use
them in any of our classes, so that we
| | 00:13 | could perform the same SQL actions in
our photograph class and our comment class,
| | 00:18 | which we're going to
be creating a little while.
| | 00:20 | We talked earlier about late static
bindings and the problems that it presents,
| | 00:23 | you want to go back and review that
movie if you have any questions about it.
| | 00:26 | But eventually, we'll be able to push
all of these common database methods up
| | 00:31 | into the database object class. Once
we get to PHP 5.3, late static bindings
| | 00:36 | are available.
| | 00:37 | Until then, the approach that we're
going to use is to put all of those into
| | 00:41 | the user class, and then copy and paste
the exact same code into our additional
| | 00:46 | classes. Now that's repeating ourself
and that's not really a great idea in
| | 00:50 | programming, but it will have to make
do until we have the ability to move
| | 00:54 | those up into a class that we can
inherit from into each of our subclasses.
| | 00:59 | So for now, let's work on making our
methods more abstract so that they are
| | 01:02 | reusable and let's start by working
on making the database table name,
| | 01:07 | abstract. So I'm going to start by
opening up user.php. Now what I'm actually
| | 01:11 | talking about here, let me open up
create, is that this SQL statement right now
| | 01:18 | is very specific to user.php. What I
would like to do is make it so that it is
| | 01:24 | reusable in a number of different
contexts. One of the first things we want to
| | 01:28 | do is say well, figure out what table
name you ought to have. We see here that
| | 01:33 | we have a protected static method
called, $table_name. So that's what
| | 01:37 | we're going to use to know
what table name this class has.
| | 01:41 | So, you might be tempted to start out
by simply putting in the curly braces and
| | 01:48 | then table name with self. That's how
we would call that. That would be the
| | 01:52 | static variable $table_name from this
object. The problem is that because of
| | 01:58 | the way PHP parses, this won't work,
the curly braces do not work like they do,
| | 02:04 | if we just simply had, $table_name.
| | 02:06 | As soon as we put that self in
front of it, it's going to break, and so
| | 02:10 | instead, what we need to do is put in
quote period and then period quote. So
| | 02:17 | we're actually just dropping out of
our double quotes for a second to append
| | 02:21 | together the table name,
and this will work for us.
| | 02:24 | So I'm just going to take that little
bit there and copy it, and we'll open up
| | 02:28 | the update. We'll have the same thing
here instead of users. We're going to
| | 02:33 | drop out of our double quotes, append
in the table name, and then open back up
| | 02:38 | our double quotes again,
and same thing for delete.
| | 02:42 | Now in the case of delete, we're going
to open up double quotes just to have
| | 02:45 | another space. We could also just as
easily put the space on this line, and get
| | 02:49 | rid of those together. That's your choice.
| | 02:51 | So that then has made these three
methods abstract enough that they will figure
| | 02:56 | out what the table name is based on
what class they are in. So the save method
| | 03:01 | doesn't need any changes, it's just
going to call update or create. But again,
| | 03:05 | this is the first step in allowing
us to be able to copy and paste these
| | 03:08 | methods into another class or to
eventually move them up into the database
| | 03:14 | object superclass.
| | 03:17 | Now that only got us halfway there
though, we also need to work on these
| | 03:21 | attributes, because the attributes
are going to be different, depending on
| | 03:24 | which class we're talking about.
| | 03:26 | So in the next movie, we're going to need
to spend some time abstracting these attributes.
| | Collapse this transcript |
| Abstracting the attributes| 00:00 | In the last movie, we saw how we can
make the create, update and delete methods
| | 00:03 | abstract, the same way we had done
with our find methods earlier, so that they
| | 00:06 | could be used by any class. Now that's
going to be enough to make the delete
| | 00:10 | method abstract, so that we can reuse it,
but the create and update methods are
| | 00:13 | going to use attributes that they
submit to SQL. So we'll need to find a way to
| | 00:17 | also make those attributes abstract. That's a
little trickier than what we did with the table name.
| | 00:21 | So here I'm inside user.php. Inside
the create method, you will see that
| | 00:26 | we have a list of the attributes keys and
then down here a list of the attribute
| | 00:31 | values. Now we would be able to write
SQL for both of these, if we can simply
| | 00:35 | come with an array that had both the
attribute keys and values in it. There are
| | 00:39 | several ways that we could
accomplish this. I'm going to show you one.
| | 00:41 | I am going to come up here above the
save method and I'm going to put in a
| | 00:46 | new method, which is going to be
called attributes and this is going to be
| | 00:48 | protected method. It's simply going
to return an associate array of the
| | 00:52 | attribute keys and their values,
instead of names. So I'll say keys.
| | 00:57 | So if we can return that array, then
we'll be able to parse through that array
| | 01:00 | to come up with these items down here.
Now let's take a look at has_attribute
| | 01:05 | that's right above it. Now in has_
attribute, we were getting a list of the
| | 01:08 | attributes to see whether an array key
existed or not, to see if something had
| | 01:12 | the attribute. We were doing
that using get_object_vars.
| | 01:15 | So for now, let's just use that. I'm
going to copy it, we'll just come down
| | 01:18 | here, return get_object_vars ($this).
So that will now return get_object_vars
| | 01:26 | as attributes. So we can actually call
that here instead $this->attributes.
| | 01:33 | Now that's essentially the same thing
as far as has_attribute is concerned,
| | 01:38 | but what it gives us is now a method
that we can call from other places in our
| | 01:41 | code to get those same attributes.
If we ever make improvements to the way
| | 01:45 | we find our attributes, which we'll do
a little later, then we'll have those
| | 01:49 | available to us also.
| | 01:50 | So now that we have our new attributes
method, let's go ahead and come down
| | 01:55 | back 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:04 | to do in order to use those attributes
is join together the array keys. So we
| | 02:10 | can use array keys to pull back all the
keys of those attributes and join them
| | 02:14 | together with a comma. That will
give us the SQL that we need there.
| | 02:18 | For the array values down here, we can
do something very similar. I'll paste in
| | 02:22 | join together and we'll include the
single quote. Notice I'm starting with a
| | 02:26 | single quote here, single quote/comma/single quote
joining them together. The only difference is
| | 02:31 | that at the very end, I'll need to make
sure that I'll also close everything up
| | 02:35 | with another '). So that will make
sure that the last one has its single quote
| | 02:42 | after it and parenthesis as well. So
that will now join all the values together
| | 02:46 | and we'll have a valid SQL statement.
| | 02:49 | Now in the process, I know we lost the
code where we were escaping the values for SQL.
| | 02:53 | We'll want to keep that, but
we'll come that in just a second. For now,
| | 02:56 | let's go on down to the update method
and do the same kind of thing. So we'll
| | 03:00 | come down here and I'll do the same
sort of attribute assignment that I was
| | 03:05 | doing before. But notice that the key
value pairs that we're going to need here
| | 03:08 | are going to be a little more
complicated because we can't simply join
| | 03:11 | the keys together and then join the
values together. Instead, they will
| | 03:14 | interspersed with equal signs between
them. We can handle that by iterating
| | 03:18 | through the attributes and creating
a new array. So we'll do that first.
| | 03:22 | Before we start, we'll make a new
array called attribute_pairs. We'll go
| | 03:25 | through each of the attributes and
each one as a key and value, we'll assign
| | 03:30 | the new attribute_pairs = "{$key} =
' {$value}'". Again, I know it's not escaped;
| | 03:38 | we'll work on that in a second.
| | 03:40 | Now we can come down into our SQL
statement though and we can do a replacement
| | 03:44 | for all of these here. We'll join them
together with a single comma. Our single
| | 03:49 | quotes have been taking care of up here.
We don't need to worry about those.
| | 03:52 | We're going to join attribute_pairs now,
not attributes, and that will give us
| | 03:56 | the list that we're looking for.
| | 03:57 | Now there is one more thing we need to
be careful about, which is that when we
| | 04:00 | join these together we'll get a comma
space between them, but whatever that
| | 04:04 | last value is will have a single
quote and then it will start the word WHERE.
| | 04:10 | We need to make sure that our SQL is
valid, so we'll put a space in front of
| | 04:13 | WHERE. So it will be single quote
as the last item and then WHERE.
| | 04:17 | That's something that frequently trips
people up, when we're using the multi-line
| | 04:21 | building up SQL. So you
want to be careful about that.
| | 04:24 | So now we have abstracted out those
attributes, but in the process, we lost the
| | 04:28 | escape_value we did. So let's revisit
how we can sanitize those SQL values again.
| | 04:32 | Let's go back up to attributes
here. Now in addition to having an
| | 04:37 | array of the raw attributes, let's add
another version of this that's going to
| | 04:41 | be a method that will loop through
those attributes and escape their values and
| | 04:45 | return a new array that's
actually been sanitized. We'll call it
| | 04:49 | sanitized_attributes.
| | 04:50 | So it will simply take the database,
go through and make a new array called
| | 04:54 | clean_attributes by going through each
one of the attributes from this method,
| | 05:00 | the get_object_vars version, and go
through each one of them. As it's doing it,
| | 05:05 | it will escape the value. So now
we'll have a set of clean attributes.
| | 05:08 | Now we have a choice. We can get either the
raw ones or we can get the sanitized version.
| | 05:13 | So anywhere that we're using the
attributes to send to SQL, we'll want to use
| | 05:18 | the new version. So that's going to be
sanitized_attributes and down here in
| | 05:24 | update, same thing. We'll be
wanting to pull in the sanitized_attributes.
| | 05:28 | Up here has_attribute, we can
still just use attributes. We're not even
| | 05:31 | actually looking at the value in this
case. So we don't need to worry about
| | 05:34 | being sanitized; it's not SQL related.
But for anywhere where we're going to be
| | 05:38 | submitting values to SQL, we now have
the ability to have attributes that are
| | 05:42 | pre-sanitized for us.
| | 05:43 | Now there is one more thing. Here
inside attributes, get_object_vars is not
| | 05:48 | the best way to get the list of
attributes. In the next movie, we'll examine
| | 05:51 | the problems with get_object_vars
and we'll talk about a better approach.
| | Collapse this transcript |
| Finding the database attributes| 00:00 | In the last movie, we began the
process of abstracting our attributes that we
| | 00:03 | were using in our create and update
methods, so that we can reuse those
| | 00:07 | methods inside other classes. But when
we did that, we used get_object_vars
| | 00:12 | and that present some problems. In
this movie, we'll look at what those
| | 00:14 | problems are and find our way around them.
| | 00:16 | As we have mentioned before, the
problem with get_object_vars is that it
| | 00:20 | returns an associative array with all
attributes for the class. That includes
| | 00:24 | attributes that may not have
corresponding database fields and it also includes
| | 00:29 | private and protected attributes.
Because we're calling get_object_vars from
| | 00:32 | inside the class, so it gives us all
the object variables that it has access to.
| | 00:37 | That includes those
private and protected ones.
| | 00:40 | That's two good reasons why it's not
going to work for us. There are some ways
| | 00:44 | that you can get_object_vars from
outside the class to exclude the private
| | 00:48 | and protected ones. You can find out
information about that by looking at the
| | 00:51 | php.net website, but that's still not
going to rule out the case, when there
| | 00:55 | might be attributes that we want in
our class and we want to be able to use,
| | 00:59 | but they don't have corresponding
database fields. Because of that, really the
| | 01:03 | easiest way to work around this
problem is going to be to create another
| | 01:07 | attribute that is going to keep a list
of all the attributes that have database
| | 01:12 | fields associated with them.
| | 01:13 | So let's do that. Let's go up here to
the top and we'll put another static
| | 01:17 | variable in here. I'm going to call
it db_fields. So inside db_fields is an
| | 01:22 | array and that array is going to be
a list of all of the fields that are
| | 01:27 | database fields. That will keep track
of it. We'll have access to it then.
| | 01:31 | So now what we want to do is come back
and actually recode attributes to make
| | 01:36 | use of that. So what we'll do is
we'll go through each one of those and
| | 01:40 | we'll ask the object to return it's value
and put it into an associative array.
| | 01:44 | We know how to do this in PHP. So we have
an empty array, then we go through those
| | 01:48 | database fields. For each one, if the
property exists, then we're going to
| | 01:53 | setup the associative array equal to
whatever that value of the field is.
| | 01:58 | Now notice here, I'm using this and
I'm using the dynamic field. That's how
| | 02:03 | we're able to do that. We're able to
use a dynamic variable here. Don't let
| | 02:06 | that thrill you. In the end, we return
that new array that we have put together
| | 02:10 | of all those attributes, as our attributes.
| | 02:14 | Now, of course, the drawback to this
approach is that you have to actually list
| | 02:17 | those fields out one-by-one at the top
of each of our classes. Now if we had
| | 02:21 | something that was really complex, we
had a big object with lots and lots of
| | 02:25 | attributes, that might become cumbersome.
In that case, you can write something
| | 02:28 | that was more complex, that might use
something like SQL's show_fields_from,
| | 02:33 | what the users table. So show_fields_
from_ users would return a list. So we can
| | 02:37 | parse that and then
build that array dynamically.
| | 02:40 | But for our purposes, because we're
going to be working with fairly simple
| | 02:43 | tables. Every time we create one of
those database tables, we're going to go
| | 02:47 | ahead and list off, in the class, what
the database fields are. That's going to
| | 02:51 | be a nice easy way for us to handle
this problem. It will circumvent those
| | 02:54 | problems that we have with get_object_vars.
| | 02:57 | So once we save that, we now have a
user class that is capable of all of the CRUD.
| | 03:01 | We can create records, we can
read them, and we did that with our
| | 03:05 | find_all, find_by_id, find_by_sql. And
we can instantiate them. That's part of
| | 03:10 | the reading and turning them into objects.
We also now know how to update and delete them.
| | 03:16 | So we now have a complete well-rounded
ability to interact with our database by
| | 03:20 | using our user class. Now that we have
finished abstracting out the create
| | 03:23 | and update methods so that they
are going to be reusable inside other
| | 03:27 | classes, we're ready to move to one
of those other classes. That's the
| | 03:31 | photograph class and that's what
we'll work on in the next chapter.
| | Collapse this transcript |
|
|
10. The Photograph ClassStarting the Photograph class| 00:00 | Now that we have all the CRUD written
for our user class, we're ready to apply
| | 00:05 | those methods to our photograph class.
Now it's taken us a long time to get to
| | 00:09 | this point, but in a way, this is what
we have been working towards all along.
| | 00:12 | The intermediate PHP we learned, the
object oriented skills, working with files
| | 00:17 | and directories, uploading files and
then developing all of the CRUD for the
| | 00:21 | user model, all of that is so that
we're able now to work with the photograph class,
| | 00:25 | which will allow us to upload
photographs and work with them in an
| | 00:29 | object oriented way using those
same methods that we just wrote.
| | 00:32 | Now there is one key difference
between uploading photographs with the
| | 00:35 | photograph class that we're about to
write and the file uploading that we did a
| | 00:39 | view chapters ago. That's why we'll
be using the database in order to keep
| | 00:42 | track of the files once they are uploaded.
| | 00:44 | Previously, we just simply uploaded
them to the file system and did not have a
| | 00:47 | database keeping track of them.
We're going to combine our file uploading
| | 00:50 | skills with the create method that
we just completed. Now there are few
| | 00:54 | reasons why storing image information
in the database is going to be better
| | 00:57 | than relying on the file system alone.
| | 00:59 | First, it's easier to search and sort
images using SQL. Second, we're going to
| | 01:04 | then be able to relate other database
records to our photographs records. So
| | 01:09 | for example, when we let people make
comments on our photos, we'll able to have
| | 01:13 | an entry in the database for photograph
and then have entries for comments that
| | 01:17 | are related to it.
| | 01:18 | Since we're going to need a database,
let's start out by creating that. Now if
| | 01:21 | you remember back in chapter 5 when we
created our users table, we also granted
| | 01:26 | access privileges to gallery as a
user and we gave it a password. You might
| | 01:31 | have given it something different
than me. That's fine, but you can look in
| | 01:34 | that config.php to mind yourself of what it was.
| | 01:36 | So we have the user, the password and
the database name. We're going to use
| | 01:40 | those now, instead of logging in as
root. Now you could log in as root. If
| | 01:44 | those doesn't work for you, that's fine,
but I'm going to open up Terminal here.
| | 01:48 | In order to get to those, we're just
going to do mysql -u for the user and
| | 01:53 | instead of root, it's going to be
gallery and then --password= and here is my
| | 01:58 | password for gallery and then the
database that we want to log in to. So that
| | 02:02 | will put us directly in that database
logged in as gallery. Since we said Grant
| | 02:06 | All Privileges, we have the ability to
go ahead and create tables there as well.
| | 02:11 | So the table that we want to create,
it's going to look like this. CREATE TABLE
| | 02:14 | photographs. We're going to have an id
NOT NULL AUTO_INCREMENT PRIMARY KEY.
| | 02:19 | The file name, which will be the name of
the image file. I went ahead and told that
| | 02:24 | it's just VARCHAR (255). The image type.
You remember the type is one of the
| | 02:30 | things that is returned to us
automatically. It's the mine type; we get that
| | 02:33 | information when we do a file upload.
| | 02:35 | So we'll go head and store it in the
database, as well as the size, and then
| | 02:39 | the last thing is going to be caption.
That's going to be something that the
| | 02:41 | user will be able to supply. They can
caption the photograph. I went ahead and
| | 02:45 | just set that also. It has a 255
character limit, but you can make it text if
| | 02:49 | you wanted to allow people to write
much longer description. So for now,
| | 02:53 | I'm just going to limit it 255.
| | 02:54 | So it says Query OK. So it has now
created the table and I can confirm that
| | 02:58 | with SHOW TABLES. So now I have both
photographs and users. If say SHOW FIELDS
| | 03:05 | FROM photographs, we can actually see those
and see that they were all created properly.
| | 03:11 | So let's quit out of my SQL now and
let's switch back over to our main website.
| | 03:17 | Let's create a new file in the
includes directory. So I'll open up a new
| | 03:21 | TextMate file and save it, not in the
btb_sandbox but inside photo_gallery,
| | 03:27 | includes and we're going
to call it photograph.php.
| | 03:32 | This is where we're going to put our
php which is going to define, class
| | 03:38 | Photograph extends DatabaseObject.
Even though there is nothing in
| | 03:43 | DatabaseObject, there will be some day.
So we'll go head and do that for now.
| | 03:47 | Then at the top, you can already guess
what our attributes are going to look like.
| | 03:51 | It's very similar to what we did
for user. If you need to open up user as
| | 03:54 | a comparison, put those side-by-side
and you can see that we went ahead and
| | 03:58 | declared table name, we declared what
database fields and then each of those
| | 04:02 | database fields gets an attribute as well.
| | 04:04 | Notice also here that there is this
nice require_once for the database. That's
| | 04:08 | a good idea. Since we're going to be
using the database class, we'll go head
| | 04:11 | and require it at the top. Then last
of all, all of these common database methods
| | 04:16 | that we wrote before, they should now
all be abstracted so that we can reuse them.
| | 04:22 | So all of them should work. I'm just
going to copy them and paste them. Again,
| | 04:25 | once we have database object working,
we won't need to do that any more. So for
| | 04:30 | now, I'll just put all those in there,
I can collapse all these down, just so
| | 04:33 | they are out of the way. Here we go.
So now we have got our common database
| | 04:43 | methods. We're ready to add any new
methods that we need to photograph.
| | 04:47 | Now there is one other thing that I
want us to take care of, which is if you
| | 04:49 | remember, when we did the initialize
here, you will remember that we required
| | 04:54 | the user file. So we'll want to do the
same thing for photograph, so that it
| | 04:58 | gets loaded. Remember that we do have
a function called autoload, which is
| | 05:01 | here, which will take care of trying to find it.
| | 05:04 | But since we know we want to load it,
let's go ahead and just specifically put
| | 05:07 | that in and initialize, so that we
make sure that the photograph class gets
| | 05:10 | loaded up. The very last thing is
where we're going to upload these files to.
| | 05:14 | We want to upload them into the photo_
gallery, into public, into images and
| | 05:18 | that is where we're going to put them.
| | 05:19 | So we want to make sure that that's
writable. So let's go back here and let's
| | 05:23 | just go into... for me that's Sites/
photo_gallery and inside public. We should
| | 05:32 | be able to see images. So that is the
folder. We want to make sure that is
| | 05:37 | writable by our web server. But
right now, it doesn't look like it is.
| | 05:40 | So we want to do something like sudo
chown www.images. That for me, well at my
| | 05:46 | web server, which runs as www, I'm
going to put my password. It will let it be
| | 05:52 | able to be the owner of that file. Now
we have talked about privileges before.
| | 05:55 | If you want to do something different,
you want to make trimod 777, that works
| | 05:59 | just as well. But the important thing
is to make sure if we're about to start
| | 06:02 | uploading images into this folder, that's
the web sever has the ability to put them there.
| | 06:07 | Once we do, then we're ready to go
back to our photograph class and start
| | 06:10 | making the customization that's going
to allow it to handle uploaded files.
| | 06:14 | That's what we'll do in the next movie.
| | Collapse this transcript |
| Coding the Photograph class| 00:00 | In the last movie, we started creating
our photograph class and we did all of
| | 00:04 | the basic work that we need to do: to
have a class, to have it inherit from
| | 00:08 | database object, to have it being
loaded by initialize, and to go ahead and
| | 00:12 | bring in all of the common database
methods that we used for the user class
| | 00:18 | into our photograph class.
| | 00:20 | Now we want to start customizing it so
that we'll able to upload photographs.
| | 00:24 | Before we dive into photograph.php,
let's take a look back at btb_sandbox and
| | 00:29 | open up upload.php. I'm just going to
shrink it down a little bit, just so that
| | 00:33 | it all fits on the screen here.
| | 00:34 | Now what we essentially want to do is
take all of this code here that takes
| | 00:38 | care of the processing and uploading of
files and move that into our photograph class.
| | 00:44 | So you can always refer back to this
if you want to take a look at what we did,
| | 00:47 | but we want to take that
and now make that object oriented.
| | 00:50 | Now I'm going to be writing it from
scratch. So I'm not going to be using it as a
| | 00:53 | reference, but we're going to open
up photograph.php. To get started,
| | 00:57 | we're going to keep track of a couple
of variables that we were using in that
| | 01:01 | upload.php page.
| | 01:02 | The temp_path, remember that's
something that is provided to us when we upload
| | 01:06 | a file. We'll make that an attribute,
so that we can actually store it in the
| | 01:09 | class. We can ask the class for its temp
_path, where the file is before it's in
| | 01:14 | its final destination.
| | 01:15 | Now because it's only a sort of
temporary working variable that we're going to
| | 01:19 | be using, we're going to make it
private so that the class knows how to work
| | 01:22 | with it and can use it. But it's now
something that we're ever going to need
| | 01:25 | from outside the class. We'll only
work with files, once they are located in
| | 01:28 | their final resting place.
| | 01:30 | Then we're going to have upload
directory, which I went head and said, should
| | 01:33 | be protected. We can make it public.
That's fine. If it needs to change for
| | 01:38 | some reason, you can make it public. So
this is going to make it, so that both
| | 01:41 | photograph and any of its sub-classes
would be able to use it. I'm going to go
| | 01:45 | ahead and set that equal to "images".
| | 01:47 | The next attribute that we're going to
use is also going to look familiar to you.
| | 01:50 | I'm going to go ahead and put
upload_errors as one of our attributes so
| | 01:54 | that we have access to all of those
upload_errors right there from inside of
| | 01:58 | our class. It knows what things went wrong.
| | 02:00 | Then I'm going to add one more that's
not familiar to you but that we'll be
| | 02:03 | making use of, which is one is simply
called errors. So errors equals and it's
| | 02:08 | just an empty array. That's going to
be initialized as an empty array. Then
| | 02:12 | what we can do is as we're going to
through and trying to move the upload or
| | 02:16 | save the upload to the database, we can
catalog those errors, we can keep track
| | 02:20 | of them. Then return them to the user
and say, hey! Here is what went wrong, by
| | 02:25 | looking at the list of errors. That
way we're not limited to just these
| | 02:29 | upload_errors, but we could
add our own errors as well.
| | 02:32 | So what we're interested in coding now
is this public function attach_file.
| | 02:37 | This is a method that's going to
allow us to pass in all of FILE. And then
| | 02:43 | whatever name we have given it, I'm
going to call it an uploaded file as an
| | 02:46 | argument and that is going to be
$file. It's going to perform some error
| | 02:49 | checking on it, it's going to set
all of these object attributes up here:
| | 02:52 | filename, type, size, temp_path. All of
that is going to get set by using those
| | 02:58 | parameters that we're sent down. Then
we'll have an object that's ready to be
| | 03:02 | saved in the database.
| | 03:04 | Now don't worry about saving anything
to the database yet, we'll do that in the
| | 03:06 | second step, in the same way that we
created a user and we gave it a user name,
| | 03:11 | we gave it a password and everything.
Then we did it separately, we saved it,
| | 03:15 | we're going to do same thing here.
We're going to instantiate a file that is
| | 03:20 | ready to be saved and then we'll
actually do the saving in a separate step. So
| | 03:25 | let's take a shot at these steps.
| | 03:26 | So first of all, let's say, set object
attributes to the form parameters. We
| | 03:30 | should be able to figure this out
pretty easily. You can look at upload.php to
| | 03:34 | figure that out. Essentially, we just
wanted to take each of those variables,
| | 03:37 | temp_path, filename, type and size,
and set them equal to the information
| | 03:41 | that's been passed in using
$_FILE (['uploaded_file']).
| | 03:44 | So we're going to take you to one of
those. This is same as if we had this bit
| | 03:49 | here in front of tmp_name and so on.
You will see that we're using basename,
| | 03:54 | just like we did before in upload.php.
But we don't have any error checking in here.
| | 03:58 | So let's put some
very basic error checking in.
| | 04:01 | The first check that I'm going to do is
if there has not been a file sent in or
| | 04:06 | if it's empty or if it's not an array,
then something went wrong. There is some
| | 04:10 | argument problem with file and we can't
use it. So therefore we'll just say no
| | 04:13 | file was uploaded and return false.
| | 04:16 | So the second thing I want to check
is going to be, if php returned an
| | 04:20 | upload_error. So if the file array
that come back has an error and that error
| | 04:26 | is not 0, remember, 0 is success,
then php found a problem. So we'll just
| | 04:30 | report back, what PHP said was
wrong. We'll do that by taking that
| | 04:34 | upload_errors, finding the one that
corresponds to the value that we get back,
| | 04:39 | and putting that inside our errors
array and return false. Each time it returns false,
| | 04:43 | we'll return but we'll also be
able to check errors to see what went wrong.
| | 04:48 | Then last of all, of course, would
just be simply, if everything worked okay.
| | 04:52 | That is the case here, where we
didn't do these. Now just didn't those and
| | 04:59 | close my curly braces. I make sure
my curly braces are all lined up.
| | 05:04 | So there we go.
| | 05:05 | The very last thing I want to do is
just at the very bottom, if this all
| | 05:09 | succeeds, then let's go ahead and
just make sure we return true as a final
| | 05:12 | value. So it's consistent. We return
false, if it didn't work. We return true,
| | 05:16 | if it did work. All the attributes
have been set accordingly in the process.
| | 05:20 | Now we don't have a mechanism for
testing this yet. You could go head and write
| | 05:23 | it on your own, if you wanted. But I
think you can feel pretty confident that
| | 05:26 | it's going to work correctly because
we're pretty much just doing the same
| | 05:29 | thing, we did in that upload.php file.
There is nothing that is sort of too out
| | 05:33 | of left field here. So there may be
syntax errors. You might want to just
| | 05:36 | double check all your typing
and make sure you get on it right.
| | 05:39 | But if you put everything in there
correctly, then we should be able just to
| | 05:42 | instantiate a new photograph, tell it
to attach the file using this file, and
| | 05:47 | then we'll be able say Save as a next
step. Saving is what we'll learn how to
| | 05:51 | do in the next movie.
| | Collapse this transcript |
| Saving photographs| 00:00 | Now that we have written the method
that will take the information we have been
| | 00:03 | given in the form parameters about an
uploaded file and instantiate an object
| | 00:07 | from it, the next step is to actually
do the saving. And in this case,
| | 00:13 | doing the saving is going to involve two
steps: moving the file to its final and
| | 00:17 | permanent location, and recording an
entry in the database about where it's located.
| | 00:21 | Now there are a couple of different
ways that we could do the save. We could
| | 00:25 | write a method that was something like
this: function save with file.
| | 00:28 | In that way, we don't interfere with the
save that we already have in our common
| | 00:32 | database methods down here, and instead
have something that's completely safe,
| | 00:36 | that will take care of this
unique situation that we have here.
| | 00:39 | We also if we were using database object,
if we had late static bindings and
| | 00:44 | we had moved all of those common methods
up there, we could simply use save and
| | 00:49 | overwrite the inherited method, and if
we ever want it access to the original one,
| | 00:54 | we can call it using parent and
then save, and that will allow us to do
| | 00:58 | the save that was in the parent method.
| | 01:00 | Those are both valid approaches. What
I'm going to do instead is actually just
| | 01:04 | overwrite the existing save method. You
may remember we had save down here that
| | 01:09 | just simply says, well, the record may
or may not have an ID and based on that,
| | 01:14 | we're going to do update or create.
Well, I'm going to give it a little more
| | 01:16 | functionality in the case of photograph,
so it's going to be a little bit different.
| | 01:20 | I am going to just comment all of that
out and I'm going to say replace with a
| | 01:26 | custom save, just to remind myself,
and then up here, I'm actually going to
| | 01:30 | right a new method. I'll go ahead and
paste down some comments showing kind of
| | 01:34 | what we're after. We're still going to
do the same whether or not it has an ID.
| | 01:38 | If it has an ID then just update it. In
that case, we're probably just updating
| | 01:41 | the caption on it, we'll assume that
the file is probably not moving, and
| | 01:45 | we'll try and keep that in mind
really just to update the caption.
| | 01:51 | Then we'll have the second one which is
where the mid of it will be where we'll
| | 01:54 | make sure that there are no errors,
and if there are no errors, then
| | 01:57 | we'll attempt to move to the file, and
if the move succeeds, then we'll save a
| | 02:02 | corresponding entry to the database,
and the way that it will save that
| | 02:05 | corresponding entry is to still use
that create method. We still have that
| | 02:08 | available to us.
| | 02:09 | So we still can make use of that but
we're going to do a little bit of meteor
| | 02:13 | stuff before we get there. So let's
start to write some of that code. Make sure
| | 02:16 | that there are no errors. Well,
first of all, we can't save if there are
| | 02:19 | preexisting errors, so we can just
simply check and make sure that our error
| | 02:22 | array is already empty. Then we set
that the caption has to be limited to 255
| | 02:27 | characters. If you set here up the
same way, then you want to put something like that.
| | 02:32 | We can add an error in that case if
its greater than 255. We know that
| | 02:36 | we're going to need to know the temporary
location of the file and we're going to
| | 02:40 | need to know the file name. So in
that case we would also want to stop this
| | 02:44 | method from happening and it will
return false and tell what the errors were.
| | 02:47 | Now if all of that works, then we're
going to be ready to figure out what our
| | 02:50 | target path ought to be. So target
path I set is the side route, directory
| | 02:55 | separator inside public, and then
inside where our the upload directory is.
| | 02:59 | In this case, it's images and then the
directory separator, and then whatever
| | 03:02 | the file name is.
| | 03:03 | Now once we have that and we know where
we're going to be putting this file, we
| | 03:07 | can do an additional error check,
which is to make sure the file does not
| | 03:10 | already exist. That's another reason
that we might want to stop the process
| | 03:13 | from happening. If all of that works,
then we're in a place where we can
| | 03:18 | actually attempt to move the file.
| | 03:20 | We know how to do that from before
with move uploaded file, so we'll try and
| | 03:24 | move from the temporary path to our
target path and if that succeeds, then
| | 03:29 | we'll have success else failure, and
we can already say that if it succeeds,
| | 03:38 | then that is where this is going to
go, right. We're going to create the
| | 03:40 | database entry. If not, we're going to
fail, we're going to add a little bit
| | 03:43 | more there as well.
| | 03:45 | If the file is not moved, let's go
ahead and just put in an error that will say
| | 03:48 | the file upload failed and return false.
If it does moves, then we're going to
| | 03:52 | try and create the database entry and
we'll wrap that it in an if statement. So
| | 03:57 | if the create takes place successfully,
so then we're going to do couple of
| | 04:02 | other things.
| | 04:03 | The first is unset the temp_path.
We don't need anymore. It was just a
| | 04:07 | temporary variable, but that will help
us know that it was moved successfully,
| | 04:11 | and finally return true, just to let us
know. If you have been returning false
| | 04:15 | for every other case. This is the one
case where we'll return true and
| | 04:19 | I'll just add a note here to remind us that
that's why we deleted temp_path because
| | 04:23 | the file isn't there anymore;
it has been moved.
| | 04:26 | So that takes care of all the steps
for moving the photograph go back and
| | 04:30 | review if you need to. I'll just
scroll up at the top here. If the ID is
| | 04:34 | already set, then it's an update.
Otherwise, we're going to go through and make
| | 04:37 | sure there is no existing errors.
| | 04:39 | Make sure the caption is okay, it
doesn't necessarily have to have a caption
| | 04:43 | but it can't be more than 255 characters,
and make sure that we're not going to
| | 04:48 | run into problems with not having the
right file information, make sure the
| | 04:51 | file does not already exist, and then
finally if all of that is true, go ahead
| | 04:56 | and attempt to move the file to the new
place and if that happens, we're going
| | 05:00 | to put the entry in the database.
| | 05:02 | Now that's a lot of code, so you want
to definitely look over it carefully,
| | 05:05 | debug it, it's quite possible that I
have made a bug in there, and I'll have to
| | 05:08 | debug in just a second, but what
we're going to do now in the next movie is
| | 05:12 | actually write the upload page that's
going to be the form that'll allow us to
| | 05:16 | upload photographs, and try out these
two methods: the instantiation and the
| | 05:20 | saving of our photograph.
| | Collapse this transcript |
| Uploading photographs| 00:00 | In the last movie, we finished coding
the photograph class, which is going to
| | 00:03 | handle most of the grunt work for us
for uploading files. Now in this movie
| | 00:07 | what we need to do is code the form
that is going to allow us to upload files
| | 00:11 | and the form processing, so that we can
try our new class out and see if we can
| | 00:14 | actually upload images.
| | 00:16 | Now before we start writing up that
web form, I just want to point out to you
| | 00:19 | that I have a new folder on my desktop
called photos and this just contains
| | 00:22 | a few samples images that we're going to
be using to upload to our photo gallery.
| | 00:26 | These are included with your exercise files.
| | 00:28 | If you have a access to the exercise
files, you can use these photos or you can
| | 00:31 | use your own photos; it really doesn't
matter. You'll notice I have made these
| | 00:34 | all a fairly small file size, and
file size is something we want to keep in
| | 00:38 | mind when we're uploading files with
PHP because we do specify what the maximum
| | 00:42 | file size is.
| | 00:43 | So don't pick something that is like
5MB file and trying to upload it, if you
| | 00:47 | haven't given PHP permission to
upload things that are 5MB large. So I want
| | 00:52 | something small, just so that I make
sure that we don't run into problems.
| | 00:54 | So now let us start writing that form.
Since, we're not going to be using
| | 00:58 | test.php anymore. We're actually going
to just repurpose that. We'll make it
| | 01:02 | into photo_upload that will be the new
name, and I'll open it up, and it just
| | 01:07 | take all of these old PHP that was
in there out. So we still have the
| | 01:11 | initialization taking place, we're
still making sure someone is logged in, and
| | 01:14 | we have our header and footer.
| | 01:16 | Now we're ready to put in our form. So
I'm going to paste in the beginning of
| | 01:19 | the form for us just something very
simple, similar to what we saw before. The
| | 01:24 | form is simply going to be posting to
itself photoupload.php. Remember that we
| | 01:30 | have to specify the enclosure type as
multi-part form data because we're going
| | 01:33 | to have an enclosed file.
| | 01:35 | I have my hidden input type here with
the file size of roughly a megabyte, and
| | 01:40 | then I have my input for my file field,
and I'll call that, file upload. Just
| | 01:45 | remember that name, we'll be reusing
that. Then I'm going to let the user
| | 01:47 | specify caption that it should go
with the photo, and the submit button,
| | 01:51 | nothing out of the ordinary there.
| | 01:52 | Now let us start improving it with
some PHP. To start with, I'm just going to
| | 01:56 | put in some PHP tags here at the top
and I want you to go ahead and declare the
| | 02:01 | maximum file size up here at the top
where it's nice and easy for me to see. In
| | 02:05 | that 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:18 | It will just drop it
down in here automatically.
| | 02:21 | Now you may want to note, max_file_size
is a potential candidate for something
| | 02:24 | that could be a static attribute of
our photograph class. We could be pulling
| | 02:28 | it statically from the photograph class.
I have decided to go ahead and make it
| | 02:32 | just for this page.
| | 02:33 | Now we're really take care of our form
processing. So I'm just going to drop
| | 02:36 | down here. There we go. So it's just
a real simple. If the post is set then
| | 02:42 | we're going to do the form processing,
and if the form has been submitted, the
| | 02:45 | first thing we want to do is we want to
instantiate a new photograph and we can
| | 02:51 | attach the caption to it, photo caption.
It's going to be equal to and we're
| | 02:57 | going to get the post value for
caption and of our post super global.
| | 03:02 | We have been want to attach the photo
to it, and we can do that with our method
| | 03:05 | we called attach file and we'll pass
in from the super global files, file
| | 03:13 | upload, and remember that's got to
match up with what's here. File upload is
| | 03:17 | where we get that.
| | 03:18 | So we're going to pass in that whole
array to get sent with files to attach file.
| | 03:22 | And it will handle it from there.
We don't have to do anything else.
| | 03:25 | And now we have an object that has the
right caption. It has all the information
| | 03:30 | about the file that was uploaded.
| | 03:31 | So the only thing left to do is just
to see if it's saved or not. So if photo
| | 03:36 | saved, then success, else failure and
in each of these cases for success and
| | 03:47 | failure, let's just provide a real
simple message, the photograph was
| | 03:51 | successfully uploaded, or if it wasn't,
we'll join together whatever errors the object has.
| | 03:56 | Remember we have that array of errors.
So we'll just take them and join them
| | 03:59 | together with the br tag and that
will be the message that we give back. Of
| | 04:02 | course if we're going to do that, then
we need a way to actually output that
| | 04:06 | message. So let's come down here
right above our form, and we'll put in our
| | 04:10 | output message helper,
and it will send-in message.
| | 04:12 | Now for sending in the value of
message, we need to make sure we have that
| | 04:16 | variable set, and if it's a post
operation, it will get set but if not, it
| | 04:21 | won't. So let's just make sure that
we don't run into problems by having
| | 04:24 | message equals quote to start with.
So it should always, at least be
| | 04:28 | initialized with an empty string.
| | 04:30 | Now you may notice here that I'm not
doing an if attach file to see what are
| | 04:34 | the attached file succeeded. I
certainly could but what happens with attached
| | 04:38 | file, besides the fact that it returns
true or false is that it sets errors for us.
| | 04:43 | It sets them in that errors array.
And if you remember, I coded the photos
| | 04:46 | save method so the very first thing it
does is it checks to see if there are
| | 04:50 | existing errors.
| | 04:51 | So it does the same thing as if I done
it if then statement, this takes care of it.
| | 04:55 | Now if we wrote our attach file
differently, we might want to code it
| | 04:58 | differently, but I'm taking advantage
of the fact that those errors are set and
| | 05:02 | the save will notice and fail. So I don't
have to do a separate if/then statement here.
| | 05:07 | So now that we have all these, let us
try it out and see if can debug our code
| | 05:11 | in the process. I'll save it, close it up,
and we'll open up Firefox. Here it is.
| | 05:16 | Let's go to photo gallery, public,
admin, photoupload.php, and that is our
| | 05:24 | page it wants me to log in you may
already be logged in, secret pwd, and let me
| | 05:31 | try again to photoupload.php.
| | 05:35 | So here we're with our photo upload,
browse, and I can browse to the first one
| | 05:39 | and I'll pick bamboo.jpg and we'll
just give it a caption of bamboo. Caption
| | 05:45 | cannot be more than 255 characters long,
well I definitely was under that 255,
| | 05:49 | so we have a bug in there, let's open
up photograph.php, and here we're with
| | 05:54 | the caption and sure enough I have it.
If the link is less than 255,
| | 05:58 | and I should be saying it's greater than 255,
so there is a bug. We'll close that up.
| | 06:03 | Let us try reloading the page and we'll
re-browse to bamboo and caption bamboo.
| | 06:11 | Upload, photograph uploaded
successfully. We have not written anything to see
| | 06:15 | those. So we just have to take its
word for it, but we can also check by
| | 06:18 | checking in with MySQL and I'll use php
my admin so that I can do that quickly.
| | 06:22 | We will go into photographs and browse.
And sure enough here is bamboo.jpg,
| | 06:28 | image\jpeg, the size, and the caption.
It all got entered correctly and we can
| | 06:33 | go here and see that it is now in our
images. It did actually upload the file.
| | 06:37 | So now that our file upload is working
we're ready to have PHP actually show us
| | 06:42 | these photographs. In the next movie,
we'll work on listing up the photographs
| | Collapse this transcript |
| Listing photographs| 00:00 | Now that we have the working
photograph class and we have a form and form
| | 00:04 | processing that will upload photographs,
what we really need is something in
| | 00:07 | the admin area that will let us view
the photographs that we have uploaded and
| | 00:11 | that's what we're going to create in this movie.
| | 00:12 | Now I strongly suggest that you pause
the movie now and try it on your own.
| | 00:17 | You have all of the skills that you
need to be able to do this already without
| | 00:20 | my help. Then when you are ready come
back and I'll show you how I did it and
| | 00:24 | I'll make a few other extra points
along the way that you want to see. I really
| | 00:27 | think it is going to be best if you
try it on your own because I think
| | 00:30 | you will be able to utilize a lot of that
knowledge and help make sure that it's
| | 00:33 | really firmly cemented in your head.
| | 00:36 | Now hopefully you did pause the movie,
and you tried it for yourself and
| | 00:39 | I'm going to show you the way that I came
up with the solution. I'm going to open up TextMate,
| | 00:43 | we'll open a new window,
and I'm just going to paste in the code.
| | 00:46 | We're going to just take a look at it,
we have got the initialize step at the
| | 00:48 | top so we get all of our
classes and everything brought in.
| | 00:51 | We make sure that the user is
logged in and then we just find all the
| | 00:54 | photographs, and we call our static
find all method to do that. Now we have a
| | 00:58 | variable set that's actually an array
of instances that we created. We now have
| | 01:03 | an array that we can work with. I'll
simply make a table down here that will go
| | 01:06 | through each one. I'll use
foreach to loop through them.
| | 01:09 | So for each element in the array photos,
call each one with the variable photo
| | 01:14 | and that will be the name of the object
as it loops to the array, and then for
| | 01:18 | each one output its file name, its
caption, its size, and its type. Now notice
| | 01:22 | that I'm using colon notation here on
the foreach, not the curly brackets. So
| | 01:26 | that means down here, instead of just
having the closing curly brackets I have
| | 01:30 | int fro each with the semicolon to
wrap that up I can use either notation.
| | 01:34 | Last of all, I have got photoupload.
php as a link that will just take me to
| | 01:38 | upload a new photograph. That's a nice
user friendly feature, then notice that
| | 01:42 | I haven't put anything yet for the image
source, so we can't actually see the image yet.
| | 01:46 | I haven't told it what to display.
I'll just put an empty image tag in there.
| | 01:50 | Now let's stop and think about what the
image source ought to be for a second.
| | 01:53 | We're inside of our admin folder. So we
need to go back a directory to get into images.
| | 01:59 | So we can do ..images and
then whatever the file name is.
| | 02:04 | That will work but I think it's not the
best way to do it and let me show you, why?
| | 02:08 | If we open up photograph.php and we go
up here at the top, you will see that
| | 02:12 | we specified the upload directory here.
We gave our class knowledge about what its
| | 02:17 | upload directory is. If we were to
change that some day, let's say to photos,
| | 02:22 | then the class would say, hey, I'm
now looking in photos for everything
| | 02:25 | I'm uploading, all my new images in to this folder.
| | 02:28 | But we would have broken this page,
this page would still be looking in images
| | 02:33 | so a better way to do it would be to
ask the class to handle it for you, and
| | 02:38 | that way that knowledge just stays
inside the class. So right here below the
| | 02:41 | Save, I'm going to put in a new
method. I'm going to call public function
| | 02:45 | image_path and that's going to take
that upload directory with the directory
| | 02:49 | separator and the file name. It's going
to do it for me. In that way now, using
| | 02:53 | that object-oriented programming, I can
just call image_path back over here and
| | 02:57 | I'll get both.
| | 02:58 | So let us do that real quick, php
echo, $photo->image and asking for is
| | 03:04 | image_path. You have to have the
parenthesis now because the function is not an
| | 03:08 | attribute so we have to have those
parenthesis and we'll close the php tag.
| | 03:12 | That will now locate the file and if
that directory ever should move for some
| | 03:16 | reason, we only have to tell the
class about it, and it will trickle down
| | 03:19 | everywhere else.
| | 03:20 | Now I think it's acceptable to have
../ in front of it because we're in the
| | 03:24 | admin directory and we do want to back
out of that directory first. So let's
| | 03:27 | save this. Not in my includes file.
Let's go photo gallery, public, admin, and
| | 03:34 | let us call it list photos.php. There we are.
| | 03:41 | So let's take a look at this in a
browser. Let's switch over to Firefox real
| | 03:45 | quick. Here we're and instead of photo
upload now, we're going to go to list
| | 03:49 | photos. Call the undefined method
photograph image path. That I have not saved it.
| | 03:55 | Let's try saving that.
There we go. Now it worked.
| | 03:58 | So there we go, now we see the image.
I told it to be smaller just by telling
| | 04:02 | its size 100 so that shrunk it down.
We'll work being able to see full size
| | 04:06 | images later, but we can see all the
information. One thing that jumps out of
| | 04:09 | me is that this size number is
kind of meaningless. That's in bytes,
| | 04:13 | but normally we don't work in bytes so it will
be a lot better if we had a nicer way to see that.
| | 04:18 | So instead of just echoing the photo
size, we could do something like this.
| | 04:22 | If the size is greater than 1024, then
express it as kilobytes. Otherwise, express
| | 04:29 | it as bytes and go ahead and write
bytes after it. Now that's fine. That works.
| | 04:32 | That's certainly an improvement, but
I have in mind an even better way that
| | 04:36 | really uses the strength of
object-oriented programming.
| | 04:39 | There might be a lot of other cases
where we want to display the size in other
| | 04:42 | context. So why do we write this
every time? It's better to put it into the
| | 04:47 | object itself. So let's do that,
let's go back to the photograph, and below
| | 04:51 | image path, I'm going to add a new
method which is going to be called
| | 04:55 | size_as_text and it will go through and
it will say well if this object size is
| | 05:00 | less than 1024, display it as bytes. If
it's less than a megabyte, then display
| | 05:06 | it as kilobytes and we'll round that
number off after dividing it by how many
| | 05:10 | bytes, otherwise, we'll assume that it
is megabytes and we'll round it to one
| | 05:15 | decimal place and display it as megabytes.
| | 05:18 | So let's try that out that's our new
method size as text. So now instead of
| | 05:22 | calling size we can call size_as_
text and don't forget we need those
| | 05:26 | parenthesis after it because it is a
function not an attribute. So let's try
| | 05:31 | that now and let's reload the page.
And you know, that's something that's a
| | 05:33 | little user friendly, and we see the
strength and power of object-oriented
| | 05:37 | programming because we're able
to push that up into the object.
| | 05:40 | Now we have access to that method
anytime we want, it's right there just as
| | 05:45 | accessible as an attribute is. In the
next movie, we'll have the upload new
| | 05:49 | photograph redirect immediately back to
this page and see how we can make some
| | 05:53 | improvements where that's concerned.
| | Collapse this transcript |
| Storing messages in the Session class| 00:00 | In this movie we're going to see how we
can make an improvement to the way
| | 00:03 | our photographs are being uploaded by
storing messages in the session class.
| | 00:07 | I'll show you what I mean. So we have
coded where we can upload a new photograph,
| | 00:11 | but when we successfully upload a
photograph, it just comes back to this page
| | 00:14 | right now and shows a message saying,
"Hey! The photograph has been uploaded."
| | 00:17 | Let's try with Buddhas and we can do
Buddhas, Upload. So it sends us a message
| | 00:23 | here but what we'd really like is for
it to redirect us to this other page,
| | 00:28 | the List page. So we can do that, we know
how to do that here by instead of having
| | 00:31 | this message right after it, we'll do
our redirect_to function that we wrote
| | 00:38 | and then we can go to list_photos.php
and that will redirect us.
| | 00:42 | But when we get redirected, we'll lose
this message. The message will disappear
| | 00:47 | during the redirect, because the
redirect is actually a new request.
| | 00:49 | What we're actually doing with that function
is sending a new set of headers to the browser.
| | 00:54 | So we're telling the browser,
"Hey! Here comes a new page and we're
| | 00:57 | starting the whole cycle over again."
It's a new request response cycle. So
| | 01:01 | this gets lost. So we need a way to
store this and the way we store things in
| | 01:06 | a stateless web environment is by using
session. So what we want to do is create
| | 01:10 | a mechanism inside session that will hang on
to those values and keep them around for us.
| | 01:16 | Inside session, I'm going to make a new
attribute and we're just going to call
| | 01:19 | it message and that will allow us to
assign something to message and then
| | 01:24 | we can put it in a session and get it back
out when we're done. So the first thing
| | 01:29 | we're going to need to do is right
something in the construct method so that
| | 01:33 | automatically when we're checking the
login that we also run another method
| | 01:37 | called check_message and that will
check and see if we have any messages that
| | 01:42 | have previously been set.
| | 01:43 | So let's jump down here and we'll
put in a new private function called
| | 01:48 | check_message just like we had
check_login, this will check message,
| | 01:51 | check to see if there is something stored.
So if some message has been set, then set the
| | 01:56 | attribute message equal to whatever is
there and clear it. If there is nothing there,
| | 02:01 | then just initialize Message
with an empty string, so that we don't get
| | 02:05 | errors. It always has a value;
the value is just no message.
| | 02:08 | So that will allows us to set it up as
soon as our session is created. Remember
| | 02:12 | we're doing that automatically down
here so that a new instance is created,
| | 02:17 | it will assign any values for
a message that were waiting for us.
| | 02:20 | Now we have a way to check the message
and get it established as an attribute,
| | 02:25 | but now we also need a way to set
the message. So I'm going to make a new
| | 02:28 | public function here and I'm going to
call it just message. Not set message,
| | 02:32 | message, and that's because
I'm going to have it do dual duty.
| | 02:35 | So PHP can tell the difference
between the function called message and the
| | 02:39 | attribute called message. That's not
a problem. I have got an argument here
| | 02:43 | that's msg. That is going to be
the text of the message that is sent.
| | 02:45 | It's optional. It may not be sent. In fact,
if it is not empty and a string has been
| | 02:50 | provided 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:59 | If it was empty, then it is a get
message and we should return whatever message
| | 03:03 | was there, whatever is in the attribute.
So this function can do both.
| | 03:05 | It can both set a value and get a value
depending on whether or not an argument is
| | 03:10 | provided here.
| | 03:11 | I am just doing it to show you the
technique and show you how it can work.
| | 03:14 | You also could have something that was
called set_message and something that was
| | 03:18 | called get_message. Now, make sure you
understand why just simply setting the
| | 03:22 | attribute message equal to the
message would not work. We have to actually
| | 03:25 | store it in session.
| | 03:27 | That doesn't get stored for us
automatically. We have to make this assignment,
| | 03:31 | specifically this assignment, in
this way, to put it in a session file.
| | 03:36 | Otherwise, it's just an attribute of a
class called session. It's not actually
| | 03:40 | in the real session, so
make sure you understand that.
| | 03:43 | So now that we have that in there,
we have the ability to get messages,
| | 03:46 | we have the ability to set messages, everything
should be working. I'm going to do one
| | 03:49 | more thing for convenience down here.
I'm going to say message equals whatever
| | 03:53 | the $session->message with the
parentheses. So it's calling that function.
| | 03:59 | That's what it is going to
pull out and set to this variable.
| | 04:01 | In that way, I had this variable nice
and easy for me to get to. I don't have
| | 04:04 | to type all of this out. You could,
you could just simply do it this way.
| | 04:08 | One advantage of doing it this way is I
have the ability to overwrite this variable
| | 04:11 | if I want to, to erase it or to do
something else without interfering with
| | 04:14 | what's in the actual session. So it is
up to you if you want to do it this way.
| | 04:18 | So now that we have that coded into
session, let's go back to photo_upload and
| | 04:22 | let's add that in here. So instead now
of setting the message this way, instead
| | 04:27 | we can say, well, the session message
ought to call that function, that method,
| | 04:34 | and pass in the string to it and that
will set message equal to whatever we want.
| | 04:38 | And now we're ready for the redirect
and it will persist across it. Now,
| | 04:42 | we don't need this anymore; we don't
need to set a default message.
| | 04:45 | That will actually clear anything that
was there. We don't want to do that.
| | 04:48 | Instead, now here our output message
will display whatever was in the message
| | 04:53 | from any previous request. So we want
to take that same bit of code and put it
| | 04:57 | on the list_photos page, so that it's
also set there. So throughout our entire
| | 05:01 | application, that messaging will be
available to us. This is always set.
| | 05:05 | We don't have to set a default value for it.
It's always there; it may be empty but it's set.
| | 05:09 | Let's try it out and see how this all works.
I think it will make more sense then.
| | 05:12 | Notice that I didn't do session
message here because I'm not doing a
| | 05:16 | redirect. What I'm doing is just
setting this value right now, overwriting
| | 05:20 | anything that was there,
to be able to output it here.
| | 05:23 | Let's save that and let's upload a
new photo. So this time let's upload
| | 05:29 | flowers, and we'll call it Flowers,
Upload. Photo Uploaded Successfully and
| | 05:35 | it took me to the new page. Notice how
that worked? We set it on that other page.
| | 05:41 | This is the page that did the
processing, photo_upload. We submitted the form
| | 05:44 | back to itself. But once it was done
processing, it stored a value of the
| | 05:48 | message in a session, redirected, and
when it finished on that redirect,
| | 05:53 | it pulled that value back out,
so it was available to us.
| | 05:57 | Go through it a few times if you need to,
to make sure you understand how that
| | 05:59 | is working. But this is a nice way to
be able to pass messages across pages
| | 06:04 | even though we're redirecting and it
is a really important and useful tool to
| | 06:08 | be able to have when building websites.
| | 06:09 | Okay, let's go back to the photographs
now and in the next movie, I'll show you
| | 06:13 | how to delete photographs
that we have uploaded previously.
| | Collapse this transcript |
| Deleting photographs| 00:00 | So now we have fully worked out our
mechanism for getting photographs into the
| | 00:03 | Admin area, we also need a way that we
can actually delete photographs when we
| | 00:07 | decide that we're done with
them. That's what we'll do here.
| | 00:10 | Now, what I have in mind is that we
would put something that would just be a
| | 00:12 | Delete link here and clicking on that
Delete link will take us to a page that
| | 00:17 | will do the deleting for us in an
object-oriented way and send us back here
| | 00:22 | afterwards letting us know
that the deletion happened or not.
| | 00:25 | So let's start by going into this page,
let me hide Firefox. So it is going to
| | 00:29 | be the list_photos page, and I'm going
to start by just adding a new column to
| | 00:34 | the top, . That will just make an
empty table cell and then right after
| | 00:40 | type, we'll put a new one. That's going
to be delete_photo.php and remember we
| | 00:44 | need to pass in the ID into that Get
string, so we know which one we're going
| | 00:48 | to delete. So we'll be able to pull
that ID out of the URL and know which one
| | 00:52 | out of the Get parameters.
| | 00:54 | So we're going to put in the photo ID
there and it will just be a simple Delete link.
| | 00:57 | That will take care of everything
on this list_photos page. Now, we can
| | 01:01 | actually write the page that is going
to do the deleting. I'll just open up
| | 01:04 | TextMate, we'll make a new page, and
I'll paste this in and then I'll show you
| | 01:08 | real quick after we save it.
| | 01:10 | So I'll just save it to delete_photo.php.
We'll put it in the Admin area so
| | 01:16 | it is right there with the others. Now
that we have the code coloring there,
| | 01:20 | you'll see we have our typical
Initialize at the top, the Load and everything,
| | 01:23 | check and make sure that we're logged-in,
check and make sure that we actually
| | 01:26 | did receive an ID in that URL string.
If not, then just say no photo ID was
| | 01:31 | provided and redirect to the
index page, which is just the menu.
| | 01:35 | That reminds me that we'll need to just
very quickly go to that Index page and
| | 01:38 | we don't have any messaging here at
the top of it. We had that before for
| | 01:41 | list_photos. Remember we added this
output message, I'll just copy and paste
| | 01:46 | output message here at the top, right
above, let's do it right here after the h2.
| | 01:52 | So we'll do any messages there, if
we're going to send messages to it, we
| | 01:55 | better display them. Then we'll find
the photograph, we'll find it by the ID,
| | 02:00 | GET id, and then we'll take it. If it
does exist, if we did find it, and if
| | 02:05 | we're able to destroy it. We haven't
written this method yet, destroy.
| | 02:08 | We're going to come back to that. So
remember we need to write a method called
| | 02:11 | Destroy in the photograph.
| | 02:13 | Then if so, the message will be,
it was deleted and will redirect to list_photos.
| | 02:17 | If not, say the photo could not be
deleted and redirect to in this case index--
| | 02:21 | actually I'm going to make that
list_photos. I think that probably
| | 02:24 | makes more sense.
| | 02:25 | Then last of all, because I don't
actually have a header and footer on this
| | 02:28 | page, I'm just going to do the little
bit of housekeeping to make sure that my
| | 02:31 | database connection is closed. It
closes by itself, but it is always a good
| | 02:34 | practice to do it.
| | 02:35 | So since there is no HTML here, this
page basically does some processing and
| | 02:39 | then sends us back to one of several
pages. So this Destroy method is what
| | 02:45 | we need to revisit now. So we'll go into
the Photograph class and we'll write that Destroy method.
| | 02:50 | I also want to do something else
while we're in there, which is notice that
| | 02:53 | we're sending in GET, the ID that we
got from the URL string. But we're not
| | 02:58 | doing any kind of checking and find_by_
id before we send it to make sure that
| | 03:03 |
|
|