I came across an interesting piece of PHP code which has me a bit stumped as to why the author has chosen to do this.
function do_something($db, $post_vars){
foreach($post_vars as $key => $value{
$vars[$key] = mysqli_real_escape_string($db, $value);
}
return $vars;
}
$db = mysqli_connect("myhost","myuser","mypassw","mybd") or die("Error " . mysqli_error($link));
do_something($db, $_POST);
It got me thinking about why someone would want to pass $_POST as a variable and just not access it directly inside the function? The only benefit I could think of (and this was a bit of a long shot) was if we were to append other information to $_POST before calling the function (such as):
function do_something($db, $post_vars){
foreach($post_vars as $key => $value{
$vars[$key] = mysqli_real_escape_string($db, $value);
}
return $vars;
}
$db = mysqli_connect("myhost","myuser","mypassw","mybd") or die("Error " . mysqli_error($link));
foreach($_POST as $post_key => $post_value){
$post[$post_key] = $post_value;
}
$post['my_custom_var'] = "a";
do_something($db, $post);
There is, however, no evidence of this practise anywhere in the code. Just calls to do_something() with $_POST being passed as an arugment.
My question then is, is there any benefit in doing it like this that I've missed or did the author simply not understand that $_POST is a global variable?
A complete long shot: Is there perhaps even any well intended "later additions" they could make to this (such as my example) that would almost justify this practise or is this just a case of misunderstanding. Or perhaps is there a security implication that could justify the practise?
IMHO it's a practice of abstraction, and there are benefits:
Generality: by receiving $_POST as a parameter, the function becomes less tightly coupled to $_POST. The function may serve more scenarios & possibly be more reusable.
Inversion of control: because the function's dependency($_POST) is injected from outside, you have more control over the function. It is a bit unlikely but let's suppose your form has been updated and now you need to submit via GET method. Without modifying the function's body, passing in $_GET on the caller's side, is enough to reflect the change.
Test fixture isolation: To mock FORM inputs to test a certain code path in the function, it is better access global states (such as $_POST) in an abstracted way, so that the test itself does not bring side effects to other part of the system.
In general, there is a very good reason to pass $_POST or $_GET or whatever array you want as argument instead of accessing it through the auto-global variables. It's called "dependency injection" and it's a key feature for testable code.
Another reason to not use auto-globals (or global variables, in general) is the readability of the code.
Compare:
function do_something($db, array $post_vars) {
// many lines of code here, you don't want to read them
}
do_something($db, $_POST);
with
function do_something_else($db) {
// many lines of code here that use $_POST, you don't want to read them either
}
do_something_else($db);
In the first case its clear that function do_something() operates over the values of $_POST (or $_GET or whatever other array full of data you pass it as argument). You don't have to read the function's code to know that; all the relevant information is displayed in the function header and in the example usage.
In the second case, the behaviour of function do_something_else() depends on the content of $_POST but one cannot know this without looking at its code.
Back to the code you posted, it doesn't look like it was written having testability in mind.
Take a look only at:
foreach($_POST as $post_key => $post_value){
$post[$post_key] = $post_value;
}
It basically does $post = $_POST in more words.
It's a good idea to sanitize the $_POST Superglobal before passing it as an argument of a function, then escape it inside the function that has your query logic.
What he does is escaping every POST variable through mysqli_real_escape_string function, which makes sure you avoid SQL Injection attacks.Then he returns the array (with escaped values) by calling : return $vars;
He might have used a function to do this because he intends to repeat the steps several times throughout the application and he might just call that function and passing the variables instead of writing the code over and over again.
MAKE SURE YOU ALWAYS ESCAPE USER INPUT BEFORE MAKING ANY DATABASE CALLS.
Related
I'm attempting to dynamically access both the $_GET and $_POST arrays, among others, using variable variables. The reason I'm trying to do this is so that I can perform similar actions on multiple arrays without needing to declare specific iterations for each. I'm reasonably sure this is possible, as PHP's documentation says it is able to use variable variables to dynamically access an array, however I'm unable to get it to work. A simple demonstration is when I'm attempting to verify that a certain property has been set.
if(isset(${$this->_array}[$property])) { return ${$this->_array}[$property]; }
else { return null; }
When I run the above script I always get null, however when I statically seek the desired property, manually using $_GET or $_POST, I get the desired outcome. I have triple checked $this->_array and $property and they are returning the correct string values. Are these arrays unavailable for such access, or am I doing something wrong?
Superglobals (such as $_POST) can not be used as variable variables within functions.
You could say something like $post = $_POST; and then use 'post' and it'd work, but directly using '_POST' won't.
Superglobals cannot be referenced as variable variables inside of classes or methods, so this will work:
<?php
$var = "_GET";
print_r(${$var});
But this will not:
<?php
test();
function test() {
$var = "_GET";
print_r(${$var});
}
I suspect that there is a better way to do what you are trying to accomplish.
http://php.net/manual/en/language.variables.superglobals.php#refsect1-language.variables.superglobals-notes
Whatever you're doing wrong, using variable variables is probably making it worse. For your own sanity, please stop. They should never be deployed in production code under any circumstances. They're impossible to debug, and using them in your code is like trying to read something that someone else wrote with their feet. If they have particularly dexterous feet, then perhaps you can understand what they're doing. But 99.9999% of the time, it is better to just use normal arrays.
That being said, try $_REQUEST instead.
There's already an array that contains both $_GET and $_POST. It's named $_REQUEST. Having said that, it can also contain the contents of $_COOKIE depending on the request_order setting, but the default is just $_GET and $_POST.
You say you want to access both the $_GET and $_POST arrays, among others -- what are these 'others'? You can use $_REQUEST to check the contents of $_GET, $_POST, and $_COOKIE all at once.
you can do this but dont know if it is a good coding practice
if( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
$method = '_POST';
}
else {
$method = '_GET';
}
$data = $$method;
You can create an associative array that references both arrays, and use that.
$params = [
'_GET' => $_GET,
'_POST' => $_POST
];
Then you can use
return $params[$this->_array][$property] ?? null;
Here's a pretty obscure one; and I know that I'm reaching here - but I'm trying to find an 'elegant' solution to adding a number of variables to [effectively] the parent scope.
Here's the example:
File 1:
<?
ImportPost();
// Do something with imported variables.
?>
File 2:
<?
function ImportPOST()
{
foreach( $_POST as $Key => $Value )
VariableToParentScope($Key, $Value);
}
?>
So that I would end up with the 'simple' variable names in my first ('DoSomething') method. One thing I find myself doing over and over again is building this small foreach to perform this exact task - but I don't see many other ways to achieve it, other than placing it all in a class - which is generally preferable anyway, but let's say this is in the context of a file that is just some non-OOP PHP.
I've also considered reading the contents of 'File 1', inserting the variables before the rest of the files contents, and then running it - and while this may be the closest thing to a 'proper' implementation there is, I'm still trying to figure out if there is a simpler, or more appropriate one.
Any thoughts?
I.E. - Edit the stack? 0_o
You can use extract to build some variables from an array - here's an example:
function importVars()
{
return array('foo'=>'xyzzy', 'bar'=>'123');
}
function demo()
{
extract(importVars());
echo "foo is $foo\n";
echo "bar is $bar\n";
}
demo();
I'd be wary of doing this with external data such as from $_POST - better to carefully validate what you're bringing in.
You could use $GLOBALS, which essentially would make your variables available in the global scope:
//assuming $_POST = ['foo'=>'bar']
echo $foo; // Notice: Undefined variable
function ImportPOST()
{
foreach( $_POST as $Key => $Value )
$GLOBALS[$key] = $Value;
}
ImportPOST();
echo $foo; // "bar".
However, as you said yourself, it's bad practice to interfere the global scope in that manner.
This seems like a potential security risk to me. I would push all the vars to an array, then pass that around. Or at most, add this array to the global scope. That way, you keep all post data contained in one place, rather than at the same level as all other global variables.
I'm attempting to dynamically access both the $_GET and $_POST arrays, among others, using variable variables. The reason I'm trying to do this is so that I can perform similar actions on multiple arrays without needing to declare specific iterations for each. I'm reasonably sure this is possible, as PHP's documentation says it is able to use variable variables to dynamically access an array, however I'm unable to get it to work. A simple demonstration is when I'm attempting to verify that a certain property has been set.
if(isset(${$this->_array}[$property])) { return ${$this->_array}[$property]; }
else { return null; }
When I run the above script I always get null, however when I statically seek the desired property, manually using $_GET or $_POST, I get the desired outcome. I have triple checked $this->_array and $property and they are returning the correct string values. Are these arrays unavailable for such access, or am I doing something wrong?
Superglobals (such as $_POST) can not be used as variable variables within functions.
You could say something like $post = $_POST; and then use 'post' and it'd work, but directly using '_POST' won't.
Superglobals cannot be referenced as variable variables inside of classes or methods, so this will work:
<?php
$var = "_GET";
print_r(${$var});
But this will not:
<?php
test();
function test() {
$var = "_GET";
print_r(${$var});
}
I suspect that there is a better way to do what you are trying to accomplish.
http://php.net/manual/en/language.variables.superglobals.php#refsect1-language.variables.superglobals-notes
Whatever you're doing wrong, using variable variables is probably making it worse. For your own sanity, please stop. They should never be deployed in production code under any circumstances. They're impossible to debug, and using them in your code is like trying to read something that someone else wrote with their feet. If they have particularly dexterous feet, then perhaps you can understand what they're doing. But 99.9999% of the time, it is better to just use normal arrays.
That being said, try $_REQUEST instead.
There's already an array that contains both $_GET and $_POST. It's named $_REQUEST. Having said that, it can also contain the contents of $_COOKIE depending on the request_order setting, but the default is just $_GET and $_POST.
You say you want to access both the $_GET and $_POST arrays, among others -- what are these 'others'? You can use $_REQUEST to check the contents of $_GET, $_POST, and $_COOKIE all at once.
you can do this but dont know if it is a good coding practice
if( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
$method = '_POST';
}
else {
$method = '_GET';
}
$data = $$method;
You can create an associative array that references both arrays, and use that.
$params = [
'_GET' => $_GET,
'_POST' => $_POST
];
Then you can use
return $params[$this->_array][$property] ?? null;
I have the same question but...I'm redirecting the user depending on an if statement using headers to a dynamic page that is constructed through a function. For that function to work properly, it needs the parameters passed in the GET portion of the headers.
According to what to the answers provided, this is a bad practice. What way should I be doing it?
function page($title,$msg){
$title = $_GET['title'];
$msg = $_GET['msg'];
echo '<h1>'.$title.'</h1>';
echo '<p>';
switch($msg){
case 1:
echo 'dwasdwadawdwadwa';
break;
case 2:
echo 'wasdadwadwdad';
break;
default:
echo 'wadasdasd';
break;
}
echo '</p>';
}
ps: feel free to point out anything else you see wrong.
I found this but it doesn't really help me.
Although you aren't necessarily using the $_GET input for something that requires security considerations (in this case), it's a bad practice not to be sanitizing values from the URL.
Not only should you be checking for malicious input (especially if you are using the input to query a database), but you should be validating that expected integer values are indeed integers, and required strings are not empty.
Also, your page($title, $msg) function accepts $title and $msg and sets them, even though they are not passed by reference.
If you expect to modify the input parameters, pass them by reference.
If you need to use the input parameters, don't overwrite them immediately.
If you don't need input parameters and only use values from $_GET locally to your function, declare page() without any arguments.
The answer to the question you linked suggests that functions should not rely on any external (e.g. global) variables. $_GET and $_POST (amongst others) are 'super globals', a language feature of PHP that makes them available in any scope. This means they may be unexpectedly modified from anywhere in your scripts.
One way to help avoid this is to avoid using super globals in methods and instead - as the answer to the other question suggests - is to instead require parameters for the variables you would otherwise get from the super globals.
E.g., instead of:
function add_user() {
$user = $_GET['user'];
// ...
}
add_user();
You would use:
function add_user($user) {
// ...
}
add_user($_GET['user']);
In your situation, what you would want is:
function page($title, $msg){
echo '<h1>'.$title.'</h1>';
echo '<p>';
switch($msg){
case 1:
echo 'dwasdwadawdwadwa';
break;
case 2:
echo 'wasdadwadwdad';
break;
default:
echo 'wadasdasd';
break;
}
echo '</p>';
}
Then, when you call page you would call it as:
page($_GET['title'], $_GET['msg']);
Why do you need to use GET? you can access all the same properties if you use POST which is also more safe
Not sure if i understand your question, but here is some code i use handle my ajax calls with:
$mc = new MyClass();
echo $mc->{$_GET["operation"]}($_GET);
This means "operation" refers to your method name inside MyClass and i dont have to add a new switch statement for each method. Now i can just add a function "addRecord($args)" to MyClass, and my ajax call would look like this:
ajax_users.php?operation=addRecord&name=testuser&dob=1980-01-01
your php function receives the arguments in an array, so inside function addRecord() you have to access the variables like $args['name'] and $args['dob'], and it dosnt matter how many parameters you have to pass on to your method.
Make sure you use prepared statements here or proper escaping to prevent sql injections.
So, I don't come from a huge PHP background—and I was wondering if in well formed code, one should use the 'superglobals' directly, e.g. in the middle of some function say $_SESSION['x'] = 'y'; or if, like I'd normally do with variables, it's better to send them as arguments that can be used from there, e.g:
class Doer {
private $sess;
public function __construct(&$sess) {
$this->sess =& $sess;
}
}
$doer = new Doer($_SESSION);
and then use the Doer->sess version from within Doer and such. (The advantage of this method is that it makes clear that Doer uses $_SESSION.)
What's the accepted PHP design approach for this problem?
I do like to wrap $_SESSION, $_POST, $_GET, and $_COOKIE into OOP structures.
I use this method to centralize code that handles sanitation and validation, all of the necessary isset () checks, nonces, setcookie parameters, etc. It also allows client code to be more readable (and gives me the illusion that it's more maintainable).
It may be difficult to enforce use of this kind of structure, especially if there are multiple coders. With $_GET, $_POST, and $_COOKIE (I believe), your initialization code can copy the data, then destroy the superglobal. Maybe a clever destructor could make this possible with $_SESSION (wipe $_SESSION on load, write it back in the destructor), though I haven't tried.
I don't usually use any of these enforcement techniques, though. After getting used to it, seeing $_SESSION in code outside the session class just looks strange, and I mostly work solo.
EDIT
Here's some sample client code, in case it helps somebody. I'm sure looking at any of the major frameworks would give you better ideas...
$post = Post::load ();
$post->numeric ('member_age');
$post->email ('member_email');
$post->match ('/regex/','member_field');
$post->required ('member_first_name','member_email');
$post->inSet ('member_status',array('unemployed','retired','part-time','full-time'));
$post->money ('member_salary');
$post->register ('member_last_name'); // no specific requirements, but we want access
if ($post->isValid())
{
// do good stuff
$firstName = $post->member_first_name;
}
else
{
// do error stuff
}
Post and its friends all derive from a base class that implements the core validation code, adding their own specific functionality like form tokens, session cookie configuration, whatever.
Internally, the class holds a collection of valid data that's extracted from $_POST as the validation methods are called, then returns them as properties using a magic __get method. Failed fields can't be accessed this way. My validation methods (except required) don't fail on empty fields, and many of them use func_get_args to allow them to operate on multiple fields at once. Some of the methods (like money) automatically translate the data into custom value types.
In the error case, I have a way to transform the data into a format that can be saved in the session and used to pre-populate the form and highlight errors after redirecting to the original form.
One way to improve on this would be to store the validation info in a Form class that's used to render the form and power client-side validation, as well as cleaning the data after submission.
Modifying the contents of the superglobals is considered poor practice. While there's nothing really wrong with it, especially if the code is 100% under your control, it can lead to unexpected side effects, especially when you consider mixed-source code. For instance, if you do something like this:
$_POST['someval'] = mysql_real_escape_string($_POST['someval']);
you might expect that everywhere PHP makes that 'someval' available would also get changed, but this is not the case. The copy in $_REQUEST['someval'] will be unchanged and still the original "unsafe" version. This could lead to an unintentional injection vulnerability if you do all your escaping on $_POST, but a later library uses $_REQUEST and assumes it's been escaped already.
As such, even if you can modify them, it's best to treat the superglobals as read-only. If you have to mess with the values, maintain your own parallel copies and do whatever wrappers/access methods required to maintain that copy.
I know this question is old but I'd like to add an answer.
mario's classes to handle the inputs is awesome.
I much prefer wrapping the superglobals in some way. It can make your code MUCH easier to read and lead to better maintainability.
For example, there is some code at my current job the I hate! The session variables are used so heavily that you can't realistically change the implementation without drastically affecting the whole site.
For example,
Let's say you created a Session class specific to your application.
class Session
{
//some nice code
}
You could write something like the following
$session = new Session();
if( $session->isLoggedIn() )
{
//do some stuff
}
As opposed to this
if( $_SESSION['logged'] == true )
{
//do some stuff
}
This seems a little trivial but it's a big deal to me. Say that sometime in the future I decide that I want to change the name of the index from 'logged' to 'loggedIn'.
I now have to go to every place in the app that the session variable is used to change this. Or, I can leave it and find someway to maintain both variables.
Or what if I want to check that that user is an admin user and is logged in? I might end up checking two different variables in the session for this. But, instead I could encapsulate it into one method and shorten my code.
This helps other programmers looking at your code because it becomes easier to read and they don't have to 'think' about it as much when they look at the code. They can go to the method and see that there is only ONE way to have a logged in user. It helps you too because if you wanted to make the 'logged' in check more complex you only have to go to one place to change it instead of trying to do global finds with your IDE and trying to change it that way.
Again, this is a trivial example but depending on how you use the session this route of using methods and classes to protect access could make your life much easier to live.
I would not recommend at all passing superglobal by reference. In your class, it's unclear that what you are modifying is a session variable. Also, keep in mind that $_SESSION is available everywhere outside your class. It's so wrong from a object oriented point of view to be able to modify a variable inside a class from outside that class by modifying a variable that is not related to the class. Having public attribute is consider to be a bad practice, this is even worst.
I found my way here while researching for my new PHP framework.
Validating input is REALLY important. But still, I do often find myself falling back to code like this:
function get( $key, $default=FALSE ){
return (isset($_GET[$key]) ? $_GET[$key]:$default);
}
function post( $key, $default=FALSE ){
return (isset($_POST[$key]) ? $_POST[$key]:$default);
}
function session( $key, $default=FALSE ){
return (isset($_SESSION[$key]) ? $_SESSION[$key]:$default);
}
Which I then use like this:
$page = get('p', 'start');
$first_name = post('first_name');
$last_name = post('last_name');
$age = post('age', -1);
I have found that since I have wildly different requirements for validation for different projects, any class to handle all cases would have to be incredibly large and complex. So instead I write validation code with vanilla PHP.
This is not good use of PHP.
get $_SESSION variables directly:
$id = $_SESSION['id'];
$hash = $_SESSION['hash'];
etc.