PHP MVC Pattern - View Parameters Exploit - Full PHP 8 Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] let's talk about the mvc pattern i initially wanted to talk about mvc in the third section of the course but i decided to move it up and introduce it earlier nvc stands for model view controller and it represents architecture that separates the data and business logic from the presentation layer so let's take a look at an example of how a request would go through an mvc pattern so we have a client or a user or browser or whatever you want to call it then makes a request to the server the request goes through the controller and controller is the middle guy here that sits in between the presentation layer or views and the models its controller's job to deal with requests responses handle resources and so on model's job is to handle the business logic it manages the data of the application it can process and store the data and data can be stored in a database or any other data structure or storage system so basically model is all about the business logic data and data management of your application so model can take in the information from the controller maybe pass it down to some kind of data store like a database and then retrieve the data from the data store and pass it back to the controller so controller and model communicate with each other in this case controller passes information to the view and then view is simply rendered and displayed to the screen or to the browser or to the client in most cases views are just the php files that mostly contain html in it but views also make it easy to use templating engines like twig and blade for example now there are many different ways you can represent mvc pattern in diagrams like this for example you might see a diagram that looks something like this where controller communicates back and forth with a client which is also correct it can be represented in many different ways depending on how you understand it or how you explain it also note that views don't really have to be just the html what if you were building something with the react or vue.js frameworks in those cases you don't really have those view files right instead you have view components which are javascript files so in those cases those javascript components act kind of like views that communicate with controllers another diagram that can represent the same thing is by using something like router because when you make a request it goes through the router right it doesn't directly execute a controller it first goes through router and then router decides which controller to execute and so on so as you can see the same thing can be represented in many different ways so it doesn't matter how you represent it as long as you understand the basic idea of mvc something i want to mention is that in addition to representing mvc pattern in multiple different diagrams there can actually be multiple different implementations of mvc pattern for example in this specific implementation model communicates with controller and controller communicates with view mvc pattern could be implemented in another way where model and view communicate to each other directly and controller does not communicate with the view at all so the diagram in that case would look something like this so as you can see here model communicates with view and whenever the state of the model changes it updates the view and you can use observer pattern to do that or you can just update the view directly so if we put both implementation side by side we would get something like this in general though you will most likely and most often use the one on the right side where model does not communicate with vue but instead controller communicates with the view you don't have to implement the entire mvc pattern and then a framework around it from scratch there are a lot of great php frameworks that provide a great start point and a platform to create awesome php web apps a lot of these frameworks implement the mvc pattern but the actual implementation can be different while the main idea remains the same for example it's not fair to say that laravel is an mvc framework no laravel is not just an mvc framework laravel does implement mvc pattern in its own way but laravel is much larger and has a lot more features and functionality that you could fit in a basic mvc pattern while introducing some sort of complexity nvc pattern gives your code base a better structure by just separating it into three layers models views and controllers each individual layer can then be further divided by using other patterns in addition to mvc database abstraction is one good example of such subdivision all right enough with the concepts and let's improve our code to have a basic nvc implementation we've already implemented a small part of mvc pattern in previous lesson in the form of routes and classes which kind of act like controllers so what we need to do here first is we can simply rename these classes into controllers it is up to you how you want to name your controllers or what conventions or standards you want to follow but i prefer to add controller at the end of the controller classes so we're going to refactor this and rename it to controllers and then append the controller within the class names here and as i refactor this it automatically updated all the usages wherever these controllers are used so as you can see within my router the namespace has been updated as well as the name of the classes note that we are not going to be creating a full mvc framework from scratch this is just to demonstrate how it works so please don't use this anywhere in production all right so the next thing we need to do is that instead of returning html directly from our controller methods we need to return or render views so let's implement the basic view handling first we need a place to store our views so let's create a new directory called views and let's put it under the source directory here and then we need to create some view files so we need one view file for each of the action that needs to render something so we need one for the index method of the home controller we need one for the index method on the invoice controller and we need one for the create method on the invoice controller as well so that sounds like we need an index.php then we need the directory invoices and within the invoices we need index.php as well and we also need create.php and you can call these views whatever you want now we can simply take all this html from here and put it within the appropriate view files so this one goes within here this goes within here and this goes within here all right so the next thing we need to do is we need to actually render these views somehow from our controllers so we might have some kind of view class and we would be creating a new object of that view class right so we would do something like new view and then maybe call a render method on it they would return a string which would contain all the necessary html that we need to render on the screen so it looks like we need a class view and we need the method render now within the view constructor we need to pass in some kind of relative path to view so in this case maybe we would pass in something like index because that is the relative path to the index right it's within the views directory we have index.php if we were to pass in an index.php of the invoices then we would type in invoices slash index so let's create this class within the app namespace and within the constructor we need to accept the view and maybe an optional parameters let's promote these arguments to turn them into properties as well the next thing we need to do is we need to create this render method here so let's add that method right here and now we need to somehow render our view file into a string if we simply do something like include this view this is not going to work of course for multiple reasons the first reason is that this is a relative path and it's not the full path so this is not going to work it will try to look for this view within the same directory that this class is and it's not going to find it and it will result in warning so if i refresh the page here we're going to get this warning so let's try to fix this warning first if you remember from the previous lesson within the index.php we created this constant storage path we can do the same thing and create a view path so we can duplicate this and create view path and simply change storage to views now we can use this constant within the view class and simply add it to our include statement like so if i refresh the page now we're still getting this warning because we're missing the extension so we need to simply add in the extension here dot php let's refresh the page now and now it's working but then we have this problem here that our home controller index method is expecting to return a string but null was returned that's because we haven't returned anything from the render method we haven't returned the string now how can we return a string we cannot really return this as a string right when you include something it's actually going to evaluate that php file and run that script so essentially it will render the page as soon as the include statement is reached which is not ideal in many cases what if we want to run some code afterwards what if we want to send some headers which we'll talk about in the next lesson or run through some more additional code before finally outputting something to the screen so the goal is to render this into a string and we can do that by using output buffering so we can start the output buffering before we include the file and then get the contents of the internal buffer and return that as a string we can do that by using php's helper functions called ob start which will turn on the output buffering then we include our view file and then we can simply return the return value of ob get clean which gets the contents of the internal buffer and it also cleans it up after so now if we refresh the page that error is gone as well and the view has been rendered properly now there are a few more things we can tweak here for example what if this view doesn't exist we need to handle that properly right so we can take this and put it into some kind of view path and then include that here and then we can check if the view file doesn't exist we can simply throw some custom exception called view not found exception and let's create that class we'll overwrite the message property to set the custom message here and we'll just say view not found for now we would of course need to have the proper exception handling and all that but as i mentioned before we're not implementing a full nvc framework let's add the proper return type here and we should cast this to string so that we can always return string strictly and speaking of strictly we should enable strict types here so let's do declare strict types equals to one and we should be good to go if we refresh everything still works now let's visit the invoices page and nothing gets printed that's because we haven't updated this part here now before i do that if we go to the home controller i kind of don't like this syntax here we can improve this and make it better the thing i don't like here is i don't like this new keyword and this parenthesis around it and the render method something like this would look a lot cleaner so we can do view make and pass in the same arguments that it needs in the constructor and then we can simply call render or even better maybe we don't need to call render if we can simply cast this to a string so let's create the make method here which is going to be static and simply return new static and pass passing the view here and params and these arguments need to be same as the constructor so we need to add another one here which is an optional parameters now if we go back to the home controller we see that our id is underlining this because this returns an object of view but we are type hinting this to string so we can either call the render here like we did before and if we visit the home page everything still works or if we're simply rendering the view directly like this without any layouts we could simply add a tostring method to our view class so that any time it's treated as a string is going to call the render for us so we can go to view class here and simply add tostring magic method and simply return this render now if we go back here let's remove the render it's going to underline again because the return type of the make method is view while the return type of index is string so it doesn't match and we can fix that easily by simply casting this to string so if you refresh the page everything still works now if you don't like casting things to string you can simply remove it and remove the type hint from here or simply set the type hint to be view like this and refresh the page and everything still works and actually this looks a lot better so now let's take this and copy to the invoice controller index method and within the create method and we can simply return invoices index and invoices create let's change the type hints here to view let's refresh the page let's visit invoices and it works let's visit invoices create and it works as well now there are a couple of things that's missing with our view implementation one is that we don't have the support for the parameters yes we're accepting the parameters within our make and constructor here but we're not really using that within our views another thing that's missing is that we don't really have a layout support for example we're rendering a view file directly which means that if you want to render a full html page you have to add the full html here so we would add a full html page like this and move our content within it and now if we visit the home page we have the full html however if we wanted to do the same thing within the invoices page then we would have to copy this and paste it here and change this form to be invoices and then copy this again and move it into the create and replace this content with the form but the problem with this is that we're duplicating a lot of the code we're duplicating this whole html blocks right here the only thing that's really changing is this part right here and there are many different ways you could implement the support for layouts we're not going to do this in this lesson but i will give you some hints and you can try it yourself one way you could do this is you could extract this entire code into some kind of layout.php view file and within the body you could put some kind of placeholder something like content like this or maybe you can pick something like this that might seem more familiar from the blade and then within your view class here you could maybe add an optional parameter here something like with layout and this would be set to false by default and if it's set to true you would render a layout the same way we render a regular view here into another variable and then simply find and replace this placeholder with this content right here and this way you can render a full page with the layout or you could render just a simple view file without any layout if you wanted to make it even more customizable and pick different layouts then instead of passing a boolean value you could pass in a layout view file and by default it will be set to empty string and if it's an empty string then you're not using any layouts and if you're passing in a valid layout and if the layout view file exists you would render that into a string and then do the same thing as i mentioned before so it could be a good practice for you if you want to try this if you encounter any problems post the comments in the description and i'll help you out so let's remove this from here and let's change this back all right let's pass in some parameters from the controller to the views and access them within our view files so we go to the home controller and we can pass in some data here so let's pass in full equals to bar for now and this can be any data this can be coming from a model you could be coming from get or post variables and so on now if we go to the index.php here let's say that we want to dump that variable right here within an h1 tag now one way we can do that because these parameters are saved within the params property and we're simply including this view here this means that the view file has access to this variable which has access to the properties so we could technically do something like this we could echo out this params full and this should work if we refresh the page we see that bar is printed but this might not be ideal right you might not want to look into the params array directly and let me tell you this there are many different ways of implementing this but i'm going to show you a couple of ways so this is one way and that's not ideal another way is that because we're storing the parameters into params array and we want to access elements that stored within that array we could actually use the gettermagic function to extract the data from the params array so let's go to view class and simply implement the magicget method and return the value from the params array if it exists otherwise return null so let's replace this with this and this should work if i refresh everything works now this also doesn't feel right we don't want to be accessing data using this variable what if we wanted to do something like this and we could also get this working the reason it's underlining here is because phpstorm thinks that this variable doesn't exist right now yes it doesn't exist and we're going to get this warning but once we make it work it will still be underlined here there are ways you could avoid that you could google how to do that in phpstorm but we'll leave it as this for now so we'll switch to the view class here and one way we could make those variables available is we could simply loop over each element in the params like this and then we can use variable variables for this so we can do something like variable and then the variable key equals to value and what this does is that whatever the value of this key is which is in this case full it's going to create the variable of that name so this here will actually create the variable foo so now we'll have the full equal to whatever the value the foo equals to within this params array so if i refresh the page now we're back to normal alternatively you could also use extract function which would do the same thing and it would work so instead of this we could simply do extract this params refresh the page and it still works but you should be very careful with the extract function and even with the variable variables approach because if you pass in some user-provided data you can actually be exploited in this case we know exactly where we're passing in the keys are not user provided the keys are something that we've specified however if we passed in something like get here then this is a problem because user can pass in anything in the query string and they can actually exploit your application i will show you a simple example let's go back here and we see that we're including view path here we can break this by simply appending to the url something like view path equals the root directory we hit enter and sure enough we get this warning so what's happening here is that we're extracting user given input here and creating a variable from that and because we know the variable name which is view path which matches this variable name here this essentially creates a new variable called view path and sets the value whatever the user gave it and now this variable view path overwrites whatever the variable we set it here and causes problems in our application so that's why you should be very careful when you're using extract or variable variables if we revert this back to variable variables and refresh the page we'll get the same warning now you might think that this doesn't really give anything to the user right and let me show you how we can actually exploit this let's say that we have some kind of env file here some kind of environment variable within our root directory and this environment variable would contain your database credentials and bunch of other things so let's say that we have db pass equals to my very secure password now how would the attacker gain access to that if the attacker guesses your variable name which is not that hard that could try to traverse your directories and find your emv files or other files if you're not properly protected so instead of slash here we could pass in that dot to go one level up because this is looking at the root directory of the relative path of view path which is the views directory so if we go up one level then we can technically do dot env hit enter and there is our very secure password we could also try composer.json composerlock and so on now in production of course you would take proper measures but still when you're using variable variables like this or using extract you should make sure that you're not passing in user information and we'll talk more about security in the third section of the course so don't worry about it for now so let's change this back here refresh the page and everything is back to normal so now that we have the views and controllers working the last part is to implement the models as i mentioned before models can use database or any other data structure or data store we won't be covering models in this lesson because we haven't talked about the databases and pdo yet which we'll do in the next couple of lessons and we'll implement the model part then but basically within the store method of the invoice controller we could have an invoice model something like invoice equals to new invoice and then after we get the data from the request which is the job of the controller right we get the data from the request and we process it meaning that we could prepare this data maybe even do validation which we're going to talk about in a second but essentially once the controller has prepared the necessary data we could then pass that in to the invoice method something like invoice create or invoice store or something and pass in all the necessary data then whatever the result we get back we can return that from the controller either in the form of view or we can return it as a json so that our javascript or whatever the front end we're using can do the proper update to the screen for the user to see so i mentioned validation and you might be asking should the validation go inside the controller or should it go within the model some will say that validation is the job of the model and that it's a business logic while some may disagree now i'm not going to tell you which one is wrong or which one is right i'm simply going to share my opinion in my opinion the form validation should be the job of a controller and even better the job of a separate layer from the controller which would take care of all the form requests that would handle the validation similar to how laravel does it so we would take the validation out of the controller into another layer which is the sub layering that i was talking about earlier where you could extend your mvc further and extract your validation and form request related functionality into those form request classes and then simply get the validated data from the form request and pass it into the model and as a result of that your controllers will become thin and that's the actual goal to keep your controllers as thin as possible so let me know what you think about the mvc pattern and whether you like it or not in the comments i hope this was helpful and answered some of the questions you might have had with the mvc pattern thank you so much for watching if you enjoy my content please give my videos thumbs up share and subscribe and i will see you next time
Info
Channel: Program With Gio
Views: 36,704
Rating: undefined out of 5
Keywords: advanced php course, learn php the right way, object oriented php, php, php course, php in 2021, php oop tutorial for beginners full, php tutorial, php8, intro to mvc, mvc tutorial, model view controller in php, mvc pattern
Id: QiO0uUwOiBg
Channel Id: undefined
Length: 22min 16sec (1336 seconds)
Published: Tue Jun 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.