Lets say I have an index.php file and some $_GET variables. After a few hundred lines of code I call a method, with the variables as parameters.
Should I validate the variables on top of everything, or should I validate them inside the class/method I call?
2 things in mind:
Avoiding to validate the variables multiple times, everywhere..
Having multiple sources, not only $_GET, and multiple calls to such a method from different files.
Some code:
<?php
function do_something($string) {
// Validate $string here?
}
// ...or here, before using it?
$result = do_something($_GET['some_string']);
This is a question where's no standard solution possible.
You could write yourself a helper class (i recommend this since this is a solution with less maintanance and best flexibility) which is called at the very first beginning of your index.php file, as some kind as a "contract" which is like:
<?
require_once "validator.php";
$validator = new Validator();
$validated = $validator->validateGet($_GET);
// all the remaining site's php code goes here
?>
this class could return anything you want, such like a boolean indicating whether every variable is okay or not, or an array containing the values with removed tags, etc.
Another barrier for cross site scripting and/or SQL injection should be prepared statements: http://php.net/manual/de/pdo.prepared-statements.php
All your SQL queries should also be contained in a external utilities class called ProductDataAccessObject (ProductDAO) or ProductQuerier, etc., which is also for structural/maintanance reasons.
But there's no rule that says "you must validate your variables at the very first beginning or at time of use"
Validate at the very first point when you are receiving $_GET at the entry level so that you are sure for the below code at later stage as well-
// Validate $_GET['some_string'] HERE
$result = do_something($_GET['some_string']);
If you validate here -
function do_something($string) {
// Validate $string here?
}
then there is a possibility that u miss the validation and it will open a loop hole in the code as validation is available only to the method this time.
If you are setting some values for the database, it is a good practice to double check the data and make it safe from code injections.
You can validate on top of the page your every single variable with a one line
$_GET = array_map("mysqli_real_escape_string",$_GET);
Array_map applies one function over every value of an array which in our case is applying mysqli_real_escape_string to the array $_GET
IMPORTANT:
Please do note this is only for sanitization and not validation
You need to validate every variable by your own, for example if what is being sent in an integer, make sure to use intval to validate it
Refer to this question for more information: Sanitization and Validation
I'm not satisfied with your answers yet, I did not ask HOW to validate, I did ask WHERE to do it.
Here is my own suggestion:
As I think the times for procedural coding in PHP are finally over (!!), I dont have any logic inside of my index.php, all logic goes into controller classes.
So you have a data Sender, and data Reciever.
As a Reciever (not only in PHP, it's something very common in realife, too), I have to validate the information sent by the Sender. The Reciever does not trust anybody (this is important in APIs for example). Therefore, validation has to be inside the methods you create, not at the top of index.php files or outside of a class. Imagine someone else using your method, is he going to validate the arguments, or has it been YOUR task? I think it's up to you, so you (the Reciever!) can throw Exceptions.
I also like to keep my data ($_GET, $_POST, ...) as raw as possible outside of the controller. Imagine you have a method which needs validated data at line 100, and a method at line 200 which needs raw data. Now on liee 5 you changed the raw into sanitized. => You have to keep two variables, $data and $data_raw, which is unnecassary overhead.
Think about it
Related
I've tried to understand OOP for a while now (although haven't had much spare time to do much). While the cars and books analogies helped me understand the concept, I have kept failing trying to find a real world scenario (relating to a PHP program with database access).
Here is my most recent attempt at using OOP. It is a simple program submitting a user message to a database.
require_once('init.php');
require_once('Classes.php');
$message = new ContactMessage($db);
if(!$message->validateForm()){
$message -> returnSessionError('Failed to validate your form. Please try again');
header('Location: ../index.php?p=contact');
}else if($message->checkSubmissions(3,10) == false){ //form info okay, check if ip has submitted more than the allowed times. Sets max for 5mins and 24hrs respectively.
if($message->max5mins == true){ //maximum allowed messages in 5min period
$message ->returnSessionError('Too many messages have been sent from the same IP address.
Please wait at least 5 minutes and try again.');
header('Location: ../index.php?p=contact');
}elseif($message->max24hrs == true) { //max allowed in a day
$message ->returnSessionError('To prevent spam, your IP address has been blocked for 24 hours. Please try again later.');
header('Location: ../index.php?p=contact');
}
}else{ //everything is fine, add to database.
if($message -> insertToDB()){
$message -> returnSuccess('Thank you for your message, I\'ll get back to you ASAP.');
header('Location: ../index.php?p=contact');
}else{
$message -> returnSessionError('Something has gone wrong in our server - Please try again later.');
header('Location: ../index.php?p=contact');
}
}
To me, I'm still seeing my code as using a bunch of functions, except now it's wrapped around a Class. Is this the correct use of OOP, or am I just pretending to use it?
Thanks
In terms of OOP, you're doing it wrong because you're mixing concepts and responsibilities.
What you're doing here is dealing with data validation, including both input's and record's
The form validator basically consists of two parts:
Input validator
It basically checks if values are not empty, their maximal or minimal length.
Record Validator
It basically queries a storage to find out about record existence and generates appropriate error message.
Form Validator itself
Its a bridge between input and record validators. It basically check if fields are valid, then starts checking for records. If both inputs and records are valid, then its isValid() method returns true, otherwise it returns false and populates an array with error messages.
$dataMapper = new ContactMapper($pdo);
$inputValidator = new InputValidator();
$recordValidator = new RecordValidator($dataMapper);
$formValidator = new FormValidator($inputValidator, $recordValidator);
if ($formValidator->isValid($data)) {
if ($dataMapper->insert($data)){
// Success, do something like a redirect
} else {
// Failed to insert
}
} else {
print_r($formValidator->getErrors());
}
What would you gain here?
In terms of OOP, you're adhering to the Single-Responsibility Principle and Separation of Concerns at the same time, because you do encapsulate separated responsibility within a class that serves it. Thus you'll be able to modify one part of an application without altering another one.
Dealing with storage logic - is another responsibility too
And that should be basically encapsulated within a Mapper that abstract an access to a table.
Assumptions
I suppose this file of yours is, alone, just responsible for the execution of this script. No others scripts, neither HTML codes. Let's call it "post.php".
Answering the title question
In the OOP paradigm, you ALWAYS create your code oriented, not just when you can reuse code.
Answering the body question
In my opinion, in order for you to have a good OOP implementation, all scripts must be inside classes, except those that call the methods, and whatever else you need and can't put inside the classes (sorry, it's difficult to be more specific in the latter). You have two possibilities:
GET pages: get infos from the server and mix with the views (i.e. HTMLs; main methods in others languages), creating dinamic pages;
POST pages: targets from yours forms; in separated pages without any HTML, post infos to the server, like yours "post.php".
So, your script should be inside some class, it could be the ContactMessage, and in the "post.php", you just call the method of ContactMessage, something like postMessage, that does all this stuff.
Being more clear, i would create a postMessage method inside the ContactMessage class and call validateForm, checkSubmissions, insertToDB... from other classes (instead of the own ContactMessage), to create the "Single Responsibility" like the others said. One class responsible for the validation, one to abstract the DB and so on...
Final considerations
In my short experience, a real scenario it's a bit more complex than this, but you go adapting along the way corresponding to the needs.
One last thing: i would put all the redirections outside the class, in the "post.php", and would be just two possible redirections, one if fails and one if succeeds.
I'm reading a book on php security, and on input validation chapter there's a small section that talks about only allowing expected input.
This is the code that they show:
<?php
$expected = array( 'carModel', 'year', 'bodyStyle' );
foreach( $expected AS $key ) {
if ( !empty( $_POST[ $key ] ) ) {
${$key} = $_POST[ $key ];
}
else {
${$key} = NULL;
}
}
?>
I'm kind of confused, there's a small paragraph that explains what the code does. For what I get it assigns a value from the array as a key to $_POST. It also says that the array should be done programatically copied out of the GPC array.
What I don't understand is in what cases should I use this? And what is the GPC array?
GPC = Get Post Cookie, it's referring to variables coming from the user/browser. So instead of using $_GET, $_POST, $_COOKIE you should be cleaning and validating that data into a variable(s) that you can trust and know is clean.
As for the suggestion, what they are doing is limiting what your code has access to. In the above code example, you would probably have a form on the page with elements named carMOdel, year, and bodyStyle. What the code here is doing is restricting your code to ONLY interact with those 3 elements.
This prevents someone from passing extra parameters to your page in an attempt to inject code or some sort of SQL injection attack or any other number of things. In a simple example like this it might not make sense. But there are cases where people are taking form/api requests and running loops over everything in one of GPC arrays and doing stuff with anything in there. I would suggest not doing that to begin with.
This is just 1 of MANY things to protect your server/database. When developing webapps you should take the stance of trusting NOTHING that comes from the user side.
As far as security goes, OWASP is a great source for learning. here is a little cheat sheet that is in the works for php.
The code creates variables from data in the $_POST array. The names of the variables are taken from the keys of the $_POST array. PHP calls this (i.e. naming variables dynamically) variable variables.
This is usually a bad idea, because you do not control, which keys are present in the $_POST array, and thus, which variables are created. The user of your website controls this. A malicious user might name the POST variables in such a way that they overwrite variables that you intended for different purposes.
The book suggests to allow keys in the $_POST array to overwrite variables in a controlled manner. That's what $expected = array('carModel', 'year', 'bodyStyle') is for. This and the following code only creates the variables $carModel, $year and $bodyStyle. If, for example, a user posts current_user_has_admin_rights=1 to you application, a variable $current_user_has_admin_rights with a value of 1 will not be created.
My suggestion is to to stay away from variable variables alltogether and instead access the POST values through the $_POST array only. This makes it clear where the value comes from, an thus makes it easier to spot if such a value is handled in an unsecure manner.
It also says that the array should be done programatically copied out of the GPC array.
This could mean that you shouldn't necessarily write:
$expected = array('carModel', 'year', 'bodyStyle');
Rather write something like:
$expected = getExpectedInput('carForm');
Where the function getExpectInput would query the database for the input that should be in the form 'carForm'. Or perhaps it could be in a file and this function would fetch that content. They basically mean, it's not a good idea to hard-code the variables in the form. Rather write them somewhere so they are easy to change. If you ever made changes to the form and added a variable or changed a variable name, you don't have to change this particular code. This means that this function is usable on different forms. The idea is to write function that that can be re-used. Not those that are dedicated to one thing. OOP.
The getExpectedInput function would probably return an array. You can name this whatever you like or use any method.
I have a very old client who is now having issues with security because of the MYSQL Injection. This client does not have enough money to change his PHP database functions to PDO or MYSQLI. Nevertheless, he suggested that he wants a function that prevents mysql injuction. He is fully aware that the function is not perfect. But, he does not have any other temporary way right now. the function that I wrote for him is called safe();. Here comes my question. How can I apply the function to all POSTs and REQUESTs in his site. His site has many files, it will take hours to change. is there anything that I can add in the Header of every file that applies my function to all POSTs and REQUESTs variables?
something that maybe looks like this :
$_POST[*] = safe($_POST[*]);
Of course, the above code does not work. but I hope you get the idea.
You can use array_map, but I doubt it'll be perfect solution:
$final = array_map( "mysql_real_escape_string", $_POST );
In the end $_POST and $_GET are just arrays.
You could do a foreach like
foreach ($_POST as $key => $value) {
safe($value);
}
if they have old php servers etc. So if you have a general file that is included over the whole website and the "normal" functions aren't an option, this could be the back-up plan.
You are describing the infamous Magic Quotes, which are still available if the server is older than PHP/5.4.0 (which I presume is the case).
Please note that they affect all POST data, including that which is not going to be injected in a SQL query.
If you prefer your safe() function, you can simply write a simple script that makes the change and call it via auto_prepend_file.
Possible duplicate of https://stackoverflow.com/questions/15664021/php-escaping-vars-posted-through-var-and-got-by-postvari-with-a-meth
As I was told, there's no universal method, but you can give it a try through foreaching the $_POST array
Can the PHP superglobal $_GET be used and work as intended outside of the form tags? For example, can I do $_GET('select box id') outside of the form tags and have it work as intended?
<?php
---Placeholder for DB login info---
switch($_GET['select box id'])
{
case "text shown for second option of select box":
$query = mysql_query("placeholder for actual query");
$row = mysql_fetch_row($query);
$textboxValue = $row[0];
break;
}
?>
Can the PHP superglobal $_GET be used and work as intended outside of the form tags?
Yes. The position of PHP code within HTML is entirely irrelevent except in determining where output will appear in a document.
$_GET['select box id']
Form controls use their names for submission keys, not ids.
mysql_query
Read the big red warning box on the documentation page for that function.
If this is for login info, you should not be using a get request anyway--you should be using post.
But at any rate, yes it should work. As long as the data is sent with the query, it should work.
That said, you may also want to do some research into some basic security aspects, such as validating and sanitizing inputs. Otherwise, you may wind up opening yourself up to some rather nasty attacks.
I would recommend the book Essential PHP Security from O'Reilly Press. I would also look into using something like MySql PDO for making database queries, as it tends to be more reliable and secure than simply using mysql_query.
Superglobal means available for use anywhere/everywhere.
For example, I am using a $_POST variable to insert data into a DB. Just before this query I have a few tests and if they are true I want to adjust that (hidden) $_POST value.
Ex.
if($baby_dragon_eats_children){
$_POST['hidden_value'] = "grapes";
}
Can $_POST['hidden_value'] be assigned a new value and then be passed to another function as $_POST and be able to access the new $_POST['hidden_value']?
Thanks
$_POST['consolidate_answers']
IF you assign a value to $_POST you should document is very clearly as it is not common nor considered "best" practice.
IF you have any extensions of PHP such as Suhosin Patch... it may block such actions..
Handle your own arrays, don't depend on $_POST!
IF need be, make a copy of $_POST and work with that.
You can assign values to $_POST, but if you do so you should document it very clearly with comments both at the point of assignment and the later point of access. Manually manipulating $_POST can break future programmers' (including your own) expectations of what is in the superglobal and where it came from.
There may be other alternatives, like:
$my_post = $_POST;
$my_post['hidden_value'] = 12345;
// In a function:
function func() {
// Emulate a superglobal
echo $GLOBALS['mypost']['hidden_value'];
}
Can $_POST['hidden_value'] be assigned a new value and then be passed to another function as $_POST and be able to access the new $_POST['hidden_value']?
It can in normal PHP.
However, extensions like the Suhosin Patch may block this.
Also, it feels wrong in general. $_POST is intended to contain the raw, incoming POST data - nothing else. It should not be modified IMO.
A better way to go would be to fetch all the data you plan to insert into the database into an array, and do the manipulations in that array instead.
You can, it will work, but don't.
Create a copy of $_POST, perform your tests on that and modify that instead. For example.
$postdata = $_POST;
if ($postdata['somevalue'] != 'someothervalue') $postdata['newvalue'] = 'anothervalue';
// ...
If you manipulate variables auto-created by PHP, it will probably come back to haunt you later on when the variable doesn't hold the data you expect it to.
Find an alternative!
The $_POST variable has a distinct responsibility. Do not abuse its globalism.
I'd say don't abuse globalism either way, even if it means changing the design you have (or have in mind).
But if you choose not to, then consider creating a dedicated global registry just for your needs.
Don't manipulate language built-ins.