Have I understood sessions/multi-dimensional arrays properly? - php

Am I doing the following correctly?
I have an array, which I want to save to a session, so I can use it later in my web application:
$data = array(
"id" => $_POST["id"],
"r1" => $_POST["r1"],
"r2" => $_POST["r2"],
"r3" => $_POST["r3"]);
I save it to a session like this:
$_SESSION['settings'] = $data;
Now, I am not sure how to make use of this later in my application.
Do I do the following
$id = $_SESSION['settings']['id'];
$r1 = $_SESSION['settings']['r1'];
or do I do the following
$data = $_SESSION['settings'];
$id = $data['id'];
$r1 = $data['r1'];
or do I do something else?

Both those methods are perfectly valid ways of doing it. It's probably worth putting some defensive coding in there however.
eg.
$id = "";
if (ISSET($SESSION["settings"]) && ISSET($SESSION["settings"]["id"])
{
$id = $SESSION["settings"]["id"];
}

You can do both as $_SESSION['settings'] points to an array, the two expressions will be identical:
// The expression...
$val = $_SESSION['settings']['id'];
// ... is an internal shorthand for ...
$tmp = $_SESSION['settings']; // $tmp never exist - just to aid explanation.
$val = $tmp['id'];

Don't forget to use session_start(); before setting/using variables.
Then set the variables as you did. Not 100% sure, but both ways should work.
When you finish working with session, dont forget to destroy it session_destroy();.

Do whatever you need to solve your problem. In your case, both ways are acceptable of working with sessions. If I were you, I would choose the first example when only need to acces 1 or 2 elements from the session and the secon example to access more than 2 (in order to type less ).

Related

Check if a variable with a name from a config file is set

In a PHP function, I need to check if a variable is set. However the variable name is, well, variable. It can be changed from within a config.php file. Looks like this:
//config.php
class config {
const array = 'name';
}
So I need to check if a variable with the name config::array (in this case $name) exists. This is what I've come up with:
$array = config::array;
if(isset($$array)) return true;
Notice the two dollar signs. Since $array == 'name', $$array becomes $name - at least in theory. I've tested this and it seems to be working as intended. However, I'm not sure if it's actually doing what I want - is it? If yes, is this a good way of doing this or is there a better one? If not, how do I do this?
Thank you!
You should do this:
$array = config::array;
if (isset($$array))
{
$array = $$array
};

Can't understand syntax error, unexpected '=' in eval()'d code

I've search different forms but didn't understand how to solve the problem first found here (first link, second link) but its giving me the error in eval. I can't figure it out how to solve in that code in foreach loop.
foreach($_POST as $key => $value) {
if(!strstr($key, 'removeFile')){
//initialize variables using eval
eval("$" . $key . " = '" . sanitize($value) . "';");
}
}
First, the issues I have with your code:
eval is very, very rarely needed, and extremely dangerous, use with caution. I've been developing in PHP for over 10 years, and never really encountered a situation that needed eval. This is no exception. Eval is not required
You're sanitizing the entire $_POST array. That's great, but there are special functions for doing that, like: filter_input_array, array_filter and many, many more... not to mention ready-made, open source projects and frameworks that already contain a solid request validation component.
Always check the return values of functions, which you seem to be doing with strstr, but be weary of functions that return different types (like strstr: it returns false if the needle isn't found, but returns 0 if the needle is found at the start of the haystack string). Your if statement might not work as intended.
You're assuming sanitize($value) values will not contain any single quotes. Why? Because if they do, you'll end up with a syntax error in your evaled string
Be that as it may, you could easily write your code using variable variables and add a simple check not to step on existing variables in scope:
$sanitized = array_filter($_POST, 'sanitize');//call sanitize on all values
foreach ($sanitized as $key => $value)
{
if (!isset($$key) && strstr($key, 'removeFile') === false)
$$key = $value;
}
But really, $_POST values belong together, they are part of the request, and should remain grouped... either in an array, or in an object of some sort. Don't assign each value to its own variable, because pretty soon you'll loose track of what variables are set and which are not. Using an unset variable creates that variable, assigning value null, so what you have now makes for very error-prone code:
//request 1: POST => id=123&foo=bar
foreach ($sanitized as $k => $v)
$$k = $v;
$query = 'SELECT x, y, z FROM tbl WHERE id = ?';//using posted ID as value
$stmt = $db->prepare($query);
$stmt->execute(array($id));
All is well, because $id was set, but never trust the network, don't assume that, just because $_POST is set, all the keys will be set, and their values will be correct:
//request 2: POST => foo=bar&page=2
foreach ($sanitized as $k => $v)
$$k = $v;
$query = 'SELECT x, y, z FROM tbl WHERE id = ?';//using posted ID as value
$stmt = $db->prepare($query);
$stmt->execute(array($id));//id is null
Now we have a problem. This is just one example of how your code might cause issues. Imagine the script grows a bit, and look at this:
//request 3: POST => id=123&foo=bar&page=2
foreach ($sanitized as $k => $v)
$$k = $v;
//$id is 123, $foo is bar and $page = 2
$query = 'SELECT x, y, z FROM tbl WHERE id = ? LIMIT 10';//using posted ID as value
//a lot more code containing this statement:
$page = someFunc();
$log->write('someFunc returned log: '.$page);
//more code
$offset = 10*($page-1);//<-- page is not what we expected it to be
$query .= sprintf(' OFFSET %d', $offset);
$stmt = $db->prepare($query);
$stmt->execute(array($id));
Now this may seem far-fetched, and idiotic, but believe me: all of these things happen, more than I care to know. Adding some code that accidentally overwrites an existing variable that is used further down happens all the time. Especially in procedural code. Don't just blindly unpack an array. Keep that single variable, and use the keys to avoid:
grey hair
sudden, dramatic baldness
loss of sanity
bleeding ulcers
In a work environment: catastrophic loss of data
Sudden loss of job
... because code like this makes unicorns cry, and bronies will hunt you down
As the first answer to the post you linked to, the problem is that when using double quotes PHP thinks your eval() code starts with a variable. As that is not the case you have two options. Use single quotes and remember to escape the single quotes declaring a string in the code or escape the dollar sign.
Bonus note
There exist more elegant solutions to the problem you are trying to solve. The best solution I can think of is using the extract function. This gives to two main benefits.
It works with all associative arrays
You can specify different flags that can help you distinguish the extracted variables apart and avoid variable injection.
One flag you can use is EXTR_PREFIX_ALL. This will prefix all the extracted variables with your own prefix. You would then access the variables with a prefix of 'PREFIX_' like the following:
$array = [
'variable1' => 'foo',
'variable2' => 'bar'
];
extract($array, EXTR_PREFIX_ALL, 'PREFIX_');
$value1 = $PREFIX_variable1; // Equals: foo
$value2 = $PREFIX_variable2; // Equals: bar
A little on code injection
Suppose you have some code:
$login = false;
The $login variable determines if a user is logged in or not.
Then somewhere you use the ´extract´ function with an array of the following without using any flags.
$array = [
'login' => true,
'foo' => 'bar'
];
extract($array);
Now your $login variable would be set to true and the user posting the data would have overwritten the initial setting and gained access to your website without a valid login. Bear in mind this is a over simplified example, but nonetheless valid.
To overcome this you can use the flag EXTR_SKIP or prefix them like I previously showed. The EXTR_SKIP flag will skip the array element if a variable with the same name already is defined. So now your code would not overwrite your $login variable.
extract($array, EXTR_SKIP); // Skip existing variables
// Or
extract($array, EXTR_PREFIX_ALL, 'prefix'); // Prefix them all.
Hope this can guide to the right choice for your needs.
Regards.

php session variable multidimensional associative array issue

I've looked around SO, but can't find an explanation to what is going on in my $_SESSION variables.
#ob_start();
$k=#ob_get_contents();
#ob_end_clean();
#session_start();
unset($s,$m);
$m1 = explode(" ", microtime());
$stime = $m1[1] + $m1[0];
echo $k;
$_SESSION['resendConfirmation']['function'] = 'resend';
$_SESSION['resendConfirmation']['id'] = '8';
print_r($_SESSION);
outputs:
Array ( [resendConfirmation] => 8esend )
Why is it string replacing? I've never had this issue before.
What I want is thus:
Array([resendConfirmation] => Array(
[id] =>8
[function} => resend
)
)
I've never had this happen before, I'm totally confused!
UPDATE
In response to #DanRedux I've changed to two non-existent variable names to take the referencing out of the equation, still the same result...
$_SESSION['resendConfirmation']['tweak'] = 'resend';
$_SESSION['resendConfirmation']['tweak2'] = '8';
Same result :(
Did a sitewide query of resendConfirmation and none were found, but once I change that array name, it all worked, baffled, but fixed...
$_SESSION['reConfirm']['function'] = 'resend';
$_SESSION['reConfirm']['id'] = '8';
print_r($_SESSION);
Since I dont really know what other sorts of shenanigans the code is up to outside of this block you gave us I would say to just try this instead:
$_SESSION['resendConfirmation'] = array('id' => 8, 'function' => 'resend');
If this also fails then there has to be something else going on outside of what you posted. Good luck!
What you think is an multidimensional array really isn't. What really happens is:
What you think is an array is really a string. After that you are trying to access the string as an array. You are trying to access the element id which doesn't exists. PHP always tries to be smarter than it should and just says: OK I'll assume you meant the first index. So basically what happens is:
<?php
$notAnArray = 'somestring';
$notAnArray['id'] = '8';
var_dump($notAnArray); // 8omestring
This is the reason you should always enable error_reporting on your development machine:
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", 1);
And never suppress errors using #. Well there are some situations where you can use #, but this really isn't one of them.

Dynamically create variables in PHP

I want to create 1 variable name, but part of the name is the value stored in $i. Same for the GET result:
$Site.$i = $_GET['site'.$i]; // Should look something like $Site1 = $GET['site1'];
Please help me understand how to do this.
If you want a set of related variables, use an array:
$site[ $i ] = $_GET['site'.$i];
Even better, your GET parameters can also be an array
HTML
<input name="site[foo]" value="bar" />
PHP
$site = $_GET[ "site" ];
print_r( $site );
output
$site = array(
"foo" => "bar"
)
If you want the indexes for the array to decided automatically then you can do
<input name="site[]" value="foo" />
<input name="site[]" value="bar" />
<input name="site[]" value="baz" />
and get $_GET[ "site" ] out as
$site = array(
0 => "foo",
1 => "bar",
2 => "baz"
);
Direct Answer to Question
This is how you can do it. Not the best idea however.
$var = "$Site$i";
$$var = $_GET['site'.$i];
This makes use of variable variables.
Alternative Maintaining Current URL Structure
Alternatively perhaps something like this might work for you:
$vars = array();
foreach($_GET as $key => $value) {
if(0 === strpos($key, 'site')) { // Only grab value if the key is prefaced by the string 'site'
// You must sanitise the value some way here eg:
// $value = filter_var($value, FILTER_SANITIZE_STRING);
$vars[] = $value;
}
}
See filter_var() man page for more information on PHP filters and sanitisation/validation.
Revised URL Structure
I think this probably best solved however by making use of HTML arrays at the point your URL is generated. For more information on HTML arrays please see the PHP man page.
This allows you to access your information like the following:
$site1 = $_GET['site'][0];
$site2 = $_GET['site'][4];
This is the most logical method of dealing with this situation.
Update also see #Mat's answer for more information on this.
This is a bad idea for several reasons:
You have to loop through $_GET to find all variables (there's no language construct to pattern-match them)
Dynamic variables names are confusing, and may open security holes.
You will find that using an array will solve the second point, and also make it a lot easier to work with the code.
The first point can be solved by only using variable names you know. Send a variable containing a count how how many "sites" there are, for example:
site1=example&site2=example2&sitecount=2
This way you know that you only need to read site1 and site2, and you donät need to examine any other GET variables.
you van use $ as $_GLOBAL like this.
${'Site' . $i} = $_GET['site' . $i];
or you can use extract
please read the warnings about exract.
You can use variable variables like this:
$varname = $Site.$i;
$$varname = $_GET['site'.$i];
Doing this is discouraged however, because this is a huge security risk. You may write classes with fields representing your values from $_GET and validating them within the class.

An easier way to define these variables?

$access_community = 1;
$access_content = 1;
$access_tools = 1;
$access_administrator = 0;
$access_moderator = 0;
Just wondering if there's an easier way to write this using an array? This seems like overkill.
Thanks!
You could either do something like (sucks for readability):
$access_community = $access_content = $access_tools = 1;
$access_administrator = $access_moderator = 0;
Or as already been said, using an array:
$access = array('community' => 1,
'content' => 1,
'tools' => 1,
'administrator' => 0,
'moderator' => 0);
If you had more variables, then something like:
$access = array( 'community' => 1, 'content' => 1, ... );
foreach ($access as $k => $v) {
$real_name = 'access_' . $k;
$$real_name = $v;
}
Might work, but it's not that nice, and probably even more overkill than your code is now. I think that what you have isn't too bad, to be honest!
If you're interested, this uses indirect references or "variable variables" to actually define new variables. I'm not too sure about scope here, however.
Of course, if you can, try and just use the array directly, rather than relying on the variables being there - arrays can be changed and passed around, unlike variables.
Because you hardly can explain what are you doing and why, we can only guess.
It looks like some ACL.
So, the only sensible way to set these variables is to store it in the database. Especially if there will be dozens of them in the future.
http://phpgacl.sourceforge.net/ is probably what are you looking for
So, your variables will be assigned with values from database.
As for the answer you asked - no, there is no other way to initialize different variables with different values. You have to explicitly set every variable value. So, you have to define a variable name and a variable value somehow. So,
$variable = value
is the most plain and way convenient way.
You can make it more complicated way, but at the core it remains the same: "variable name - variable value" pairs

Categories