I've been at this for two hours, perhaps I could ask some help.
Alright, so I have a basic $_POST variable that a user submits. As you can see below, the code first checks if a value was submitted at all, and if not sets it to a default value. If the user did submit a value, it sets a variable (later used) to the value submitted. You can see my code below.
if(!isset($_POST['pSize'])) {
$pSize = "16";
}
else {
$pSize = ($_POST['pSize']);
};
echo $pSize;
The problem with the above is that I might have 50 or so different areas that the user will submit, and it'd be much nicer to just have myFunction('name','default','value'); than to write out the above for each area. However, I've been running into a problem. Here's a few examples of things I've tried. (excuse any minor errors; I don't have the actual code I tried, just the jist of what I was getting at. The problems of the code I had were not syntax errors).
function newFunction($title, $default, $value)
if(!isset($_POST[$value])) {
$title = $default;
}
else {
$title = ($_POST[$value]);
};
newFunction('pSize','16,'24');
echo $pSize;
I soon learned that the above won't work due to the fact that variables in a function won't be able to be used outside of that function unless they're global. That makes sense, since if the variable $title could be used, it would be set to many different things depending on how many times I called the function. These things in mind, I tried to set global variables.
function newFunction($title, $default, $value)
if(!isset($_POST[$value])) {
global $title . 'Title' = $title;
...
newFunction('pSize','16,'24');
echo $pSizeTitle;
I lastly tried to set the global variable to the name of the $title I supplied for the function with the string 'Title', creating the new global variable pSizeTitle, so I could echo that variable out. And this probably would have actually worked, except for the fact that I cannot define a global variable with something appended to the end, only with a simple name, and that will not work for me since I need a new global variable for every title item I have.
Hopefully this is clear, sorry if this is an absolute noob problem, I just really can't get past this.
I think the major problem is that you are not returning any data in your function, try to do it
function newFunction($title, $default, $value)
{
if(!isset($_POST[$value])) {
$title = $default;
} else {
$title = ($_POST[$value]);
}
return $title;
//return was missed
}
function checkDefault($index, $default)
{
return isset($_POST[$index]) ? $_POST[$index] : $default;
}
$title = checkDefault("title", "my default value");
Related
Is there a safe way to auto assign the keys in a posted array? Below are two examples of wrong ways...
foreach( $_POST as $key => $value ) {
$$key = $value;
}
or
extract($_POST)
Is there a better way, or is it best to code:
$foo = $_POST('foo');
$bar = $_POST('bar');
....
for all 50 inputs on my form?
(the posted info will be inserted into a database).
One more cautious way of extracting all input fields at once is:
extract( $_POST, EXTR_OVERWRITE, "form_" );
This way all your input variables will be called $form_foo and $form_bar at least. Avoid doing that in the global scope - not because global is evil, but because nobody ever cleans up there.
However, since mostly you do that in a localized scope, you can as well apply htmlentities if for example you need all fields just for output:
extract(array_map("htmlspecialchars", $_POST), EXTR_OVERWRITE, "form_");
There is not a single reason to do it.
To handle user inputs an array is 100 times better than separate variables
I like an approach where you let dynamic getters and setters in a class do all the work for you. Here's how I would code it.
First, create a bass class to hold data:
class FormParameterHandler {
protected $parameters;
public function __construct($associative_array) {
$this->parameters = array();
foreach($associative_array as $key => $value) {
$this->{$key} = $value;
}
}
public function __get($key) {
$value = null;
if(method_exists($this, "get_$key")) {
$value = $this->{"get_$key"}();
} else {
$value = $this->parameters[$key];
}
return $value;
}
public function __set($key, $value) {
if(method_exists($this, "set_$key")) {
$this->{"set_$key"}($value);
} else {
$this->parameters[$key] = $value;
}
}
}
Next, create a specific class to use for some specific form where there is something special to validate. Use your freedom as a programmer here to implement it any way you want to. And remember, since we're using reflection to look for setter methods, we can write specific setter methods for known problem areas, like e.g. to check for equal passwords in a "register user" form:
class RegisterFormParameterHandler extends FormParameterHandler {
private $passwords_are_equal = null;
public function __construct($register_form_parameters) {
parent::__construct($register_form_parameters);
}
public function has_equal_passwords() {
return $this->passwords_are_equal;
}
public function set_password($password) {
$this->parameters['password'] = $password;
$this->compare_passwords();
}
public function set_password_repeat($password_repeat) {
$this->parameters['password_repeat'] = $password_repeat;
$this->compare_passwords();
}
private function compare_passwords() {
if(isset($this->parameters['password']) && isset($this->parameters['password_repeat'])) {
$this->passwords_are_equal = ($this->parameters['password'] === $this->parameters['password_repeat']);
}
}
}
Finally, use the derived class in a "register user" flow, to easily find out if the two entered passwords match:
$registerFormParameterHandler = new RegisterFormParameterHandler($_POST);
if($registerFormParameterHandler->has_equal_passwords()) {
print "are equal";
//register user
} else {
print "are not equal";
}
You can test this by creating an HTML form that has one input field with the name "password", and another input field with the name "password_repeat".
To access any of the form data, use your form data object variable name, followed by the access operator "dash larger than" -> , followed by the name of the parameter. In the example above, if there was an input field named "user_name", it would be accessed through a call to
$registerFormParameterHandler->user_name
Rr, if you have defined the name of the field you want to get in some other variable, use reflection:
$registerFormParameterHandler->{$settings['form_data_user_name']}
Have fun! :)
A safe way to extract variables into the local scope is not to. You're injecting variables into your local scope, which is a problem however you do it. Even if you limit the variables to only a few select ones that won't clash with other variable names in the scope now, if you start adding elements to your form you may be in trouble later.
Arrays are specifically for holding an unlimited amount of named values without crowding the variable namespace. Use them! You may have to type a little more, but that's par for the course.
While it is best to refer to them with $_POST['variablename'], it is possible to expand only the variables you are expecting.
$expected = array('name', 'telephone', /* etc */);
foreach ($_POST as $key => $value) {
if (!in_array($key, $expected)) {
continue;
}
${$key} = $value;
}
Or, I prefer this:
foreach ($_POST as $key => $value) {
switch ($key) {
case 'name':
case 'telephone':
/* etc. */
${$key} = $value;
break;
default:
break;
}
}
The answer to your question depends on the computer, language, and security knowledge of the programmer. The opening sequence of processing $_POST is kind of like the opening move in a game of chess. Many use foreach loops without realizing that foreach will make a copy of the contents of $_POST the way you have it used (Programming PHP: Chapter 5, p.128-129). Wouldn't it be funny if you caused a buffer overflow simply by using foreach!
One commenter implied that everything should just be worked with inside of the $_POST superglobal. There are some merits to this... However, forgetting cache memory for a moment, access to array values is slower than direct access to a variable.
Since you have fifty (50) controls to validate (with potentially large contents), I might not want to take that array access performance hit more than 50 times (the original access hits). Moreover, if you are concerned about writing secure input validation routines, keeping your dirty laundry (non-validated input) separate from your clean (validated input) laundry is a good idea. That said, you may need a clean array anyway (hence the $_POST advocate's response), but at least you are reducing risk in the process by keeping the hopefully good separate from the potentially bad.
Is there a safe way to auto assign the keys in a posted array?
I might start like this:
Function library for this example.
function all_controls_submitted($controls) {
$postKeys = array_keys($_POST);
foreach($controls as $key) {
if(! array_key_exists($key, $postKeys)) {
return false;
}
}
return true;
}
function all_controls_set($controls) {
foreach($controls as $key) {
if(! isset($_POST[$key])) {
return false;
}
}
return true;
}
if(is_array($_SERVER) && isset($_SERVER['REQUEST_METHOD'], $_SERVER[REQUEST_URI]) && $_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/contact.php') {
$newForm = true;
} elseif (is_array($_SERVER) && isset($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/contact.php') {
$newForm = false;
$controlNames = array('firstName', 'lastName', 'e-mail', 'company', 'subject', 'message', 'captcha');
define('NUM_CONTROLS_EXPECTED', count($controlNames)); //Seven (7)
if(is_array($_POST) && count($_POST) === NUM_CONTROLS_EXPECTED && all_controls_submitted($controlNames) && all_controls_set($controlNames)) {
//Begin input validation
}
} else {
header('location: http://www.nsa.gov');
}
Notice that I prep things with the $controlNames array, therefore I do not have to ask $_POST for the keys. After all, I should know them! :-) The two user-defined functions, all_controls_submitted() and all_controls_set() are two fundamental questions that should be asked before trying to use any values in $_POST (I say, anyway). Admittedly, I do use $_POST in all_controls_submitted(), but only to obtain the names of the controls submitted, not the values.
$postKeys = array_keys($_POST);
However, who is to say that the control names themselves could not be poisonous and in need of input validation?!! Same goes for values in $_SERVER. See, a chess game.
Is there a safe way to auto assign the keys in a posted array? I cannot tell you for certain, but perhaps something like the code above could help? You'd have the keys, at least.
Programming PHP: Chapter 5, p.125
Try this inbuilt method/function filter_input
Reference URL: php.net function filter input
I have a series of variables in php:
move1A = $row['column'];
move2A = $row['column'];
move3A = $row['column'];
etc.
I want to create a variable that will represent these variables and check if it is NULL. I have spent quite a bit of time looking, and although I believe that variable variables may be the key to my problem. So far I have tried:
$current_move_check = 'move'.$moveCounter.'A';
and
$current_move_check = '$move'.$moveCounter.'A';
Neither seem to work. Any suggestions for making something like this work? Thanks!
UPDATE:
So I'm trying to loop the moveXA variables based on user input and I need to run different script whether it is null or set.
I thought that:
elseif (!$$current_move_check) {
and
elseif ($$current_move_check) {
would work but they seem to not be outputting as expected.
Considering your update, I'd really suggest you to use an array, rather than the variable variables trick. Your code would makes more sense and be easier to maintain :
$count = 0;
$moveA[++$count] = $row['column'];
$moveA[++$count] = $row[...];
$moveA[++$count] = $row[...];
...
foreach ($moveA as $key => $value) {
if ($value) { // = $$current_move_check
} else { // = !$$current_move_check
}
}
As #MatsLindh pointed out in its comment : "Variable variables are never a good idea. Unless you know when it makes sense to break that rule, don't."
$current_move_check = 'move'.$moveCounter.'A';
echo $$current_move_check;
now you can check this as well like
if($$current_move_check!=NULL)
{
// do your code
}
I have an interesting situation. I am using a form that is included on multiple pages (for simplicity and to reduce duplication) and this form in some areas is populated with values from a DB. However, not all of these values will always be present. For instance, I could be doing something to the effect of:
<?php echo set_value('first_name', $first_name); ?>
and this would work fine where the values exist, but $user is not always set, since they may be typing their name in for the first time. Yes you can do isset($first_name) && $first_name inside an if statement (shorthand or regular)
I am trying to write a helper function to check if a variable isset and if it's not null. I would ideally like to do something like varIsset('first_name'), where first_name is an actual variable name $first_name and the function would take in the string, turn it into the intended variable $first_name and check if it's set and not null. If it passes the requirements, then return that variables value (in this case 'test'). If it doesn't pass the requirements, meaining it's not set or is null, then the function would return '{blank}'.
I am using CodeIgniter if that helps, will be switching to Laravel in the somewhat near future. Any help is appreciated. Here is what I've put together so far, but to no avail.
function varIsset($var = '')
{
foreach (get_defined_vars() as $val) {
if ($val == $var) {
if (isset($val) && $val) {
echo $val;
}
break;
}
}
die;
}
Here is an example usage:
<?php
if (varIsset('user_id') == 100) {
// do something
}
?>
I would use arrays and check for array keys myself (or initialize all my variables...), but for your function you could use something like:
function varIsset($var)
{
global $$var;
return isset($$var) && !empty($$var);
}
Check out the manual on variable variables. You need to use global $$var; to get around the scope problem, so it's a bit of a nasty solution. See a working example here.
Edit: If you need the value returned, you could do something like:
function valueVar($var)
{
global $$var;
return (isset($$var) && !empty($$var)) ? $$var : NULL;
}
But to be honest, using variables like that when they might or might not exist seems a bit wrong to me.
It would be a better approach to introduce a context in which you want to search, e.g.:
function varIsset($name, array $context)
{
return !empty($context[$name]);
}
The context is then populated with your database results before rendering takes place. Btw, empty() has a small caveat with the string value "0"; in those cases it might be a better approach to use this logic:
return isset($context[$name]) && strlen($name);
Try:
<?php
function varIsset($string){
global $$string;
return empty($$string) ? 0 : 1;
}
$what = 'good';
echo 'what:'.varIsset('what').'; now:'.varIsset('now');
?>
I am a still a newbie when it comes to using YII, but I been working with session variables for the past few days, and I can't seem to grasp to the concept behind my error. Any advice will be appreciated.
My add function works perfectly so far, for my current purpose of keeping track of the last 3 variables added to my session variable nutrition.
public function addSessionFavourite($pageId)
{
$page = Page::model()->findByPk($pageId);
$categoryName = $page->getCategoryNames();
if($categoryName[0] == 'Nutrition')
{
if(!isset(Yii::app()->session['nutrition']))
{
Yii::app()->session['nutrition'] = array();
}
$nutrition = Yii::app()->session['nutrition'];
array_unshift($nutrition, $pageId);
array_splice($nutrition, 3);
Yii::app()->session['nutrition'] = $nutrition;
}
My remove function doesn't seem to work at all, no matter what I try to do with it. The reason why I am transfering the session array to a temp array was to try to get around the "If a globalized variable is unset() inside of a function, only the local variable is destroyed. The variable in the calling environment will retain the same value as before unset() was called." But it was a total failure.
public function removeSessionFavourite($pageId)
{
$page = Page::model()->findByPk($pageId);
$categoryName = $page->getCategoryNames();
if($categoryName[0] == 'Nutrition')
{
if(!isset(Yii::app()->session['nutrition']))
{
return true;
}
$nutritionArray = Yii::app()->session['nutrition'];
unset($nutritionArray[$pageId]);
Yii::app()->session['nutrition'] = $nutritionArray;
}
Any advice or push toward to the correct direction will be appreciated.
I personally I have never used Yii::app()->session I normally use the Yii user and I have never had any issues with it:
Yii::app()->user->setState('test', array('a'=>1,'b'=>2));
print_r(Yii::app()->user->getState('test')); //see whole array
$test = Yii::app()->user->getState('test');
unset($test['b']);
Yii::app()->user->setState('test',$test);
print_r(Yii::app()->user->getState('test')); //only 'a'=>1 remains
Yii::app()->user->setState('test', null);
print_r(Yii::app()->user->getState('test')); //now a null value
As I put in a comment above there seems to be issues with multidimensional arrays with the session variable: https://code.google.com/p/yii/issues/detail?id=1681
Anyone has an idea if this is at all possible with PHP?
function foo($var) {
// the code here should output the value of the variable
// and the name the variable has when calling this function
}
$hello = "World";
foo($hello);
Would give me this output
varName = $hello
varValue = World
EDIT
Since most people here 'accuse' me of bad practices and global variables stuff i'm going to elaborate a little further on why we are looking for this behaviour.
the reason we are looking at this kind of behaviour is that we want to make assigning variables to our Views easier.
Most of the time we are doing this to assign variables to our view
$this->view->assign('products', $products);
$this->view->assign('members', $members);
While it would be easier and more readable to just be able to do the following and let the view be responsible to determining the variable name the assigned data gets in our views.
$this->view->assign($products);
$this->view->assign($members);
Short answer: impossible.
Long answer: you could dig through apd, bytekit, runkit, the Reflection API and debug_backtrace to see if any obscure combination would allow you to achieve this behavior.
However, the easiest way is to simply pass the variable name along with the actual variable, like you already do. It's short, it's easy to grasp, it's flexible when you need the variable to have a different name and it is way faster than any possible code that might be able to achieve the other desired behavior.
Keep it simple
removed irrelevant parts after OP edited the question
Regardless of my doubt that this is even possible, I think that forcing a programmer on how to name his variables is generally a bad idea. You will have to answer questions like
Why can't I name my variable $arrProducts instead of $products ?
You would also get into serious trouble if you want to put the return value of a function into the view. Imagine the following code in which (for whatever reason) the category needs to be lowercase:
$this->view->assign(strtolower($category));
This would not work with what you're planning.
My answer therefore: Stick to the 'verbose' way you're working, it is a lot easier to read and maintain.
If you can't live with that, you could still add a magic function to the view:
public function __set($name, $value) {
$this->assign($name, $value);
}
Then you can write
$this->view->product = $product;
I don't think there is any language where this is possible. That's simply not how variables work. There is a difference between a variable and the value it holds. Inside the function foo, you have the value, but the variable that held the value is not available. Instead, you have a new variable $var to hold that value.
Look at it like this: a variable is like a bucket with a name on it. The content (value) of the variable is what's inside the bucket. When you call a function, it comes with its own buckets (parameter names), and you pour the content of your bucket into those (well, the metaphor breaks down here because the value is copied and still available outside). Inside the function, there is no way to know about the bucket that used to hold the content.
What you're asking isn't possible. Even if it was, it would likely be considered bad practice as its the sort of thing that could easily get exploited.
If you're determined to achieve something like this, the closest you can get would be to pass the variable name as a string and reference it in the function from the $GLOBALS array.
eg
function this_aint_a_good_idea_really($var) {
print "Variable name: {$var}\n";
print "Variable contents: {$GLOBALS[$var]}\n";
}
$hello="World";
this_aint_a_good_idea_really('hello');
But as I say, that isn't really a good idea, nor is it very useful. (Frankly, almost any time you resort to using global variables, you're probably doing something wrong)
Its not impossible, you can find where a function was invoked from debug_backtrace() then tokenize a copy of the running script to extract the parameter expressions (what if the calling line is foo("hello $user, " . $indirect($user,5))?),
however whatever reason you have for trying to achieve this - its the wrong reason.
C.
Okay, time for some ugly hacks, but this is what I've got so far, I'll try to work on it a little later
<?php
class foo
{
//Public so we can test it later
public $bar;
function foo()
{
//Init the array
$this->bar = array();
}
function assign($__baz)
{
//Try to figure out the context
$context = debug_backtrace();
//assign the local array with the name and the value
//Alternately you can initialize the variable localy
//using $$__baz = $context[1]['object']->$__baz;
$this->bar[$__baz] = $context[1]['object']->$__baz;
}
}
//We need to have a calling context of a class in order for this to work
class a
{
function a()
{
}
function foobar()
{
$s = "testing";
$w = new foo();
//Reassign local variables to the class
foreach(get_defined_vars() as $name => $val)
{
$this->$name = $val;
}
//Assign the variable
$w->assign('s');
//test it
echo $w->bar['s'];
}
}
//Testrun
$a = new a();
$a->foobar();
impossible - the max. ammount of information you can get is what you see when dumping
debug_backtrace();
Maybe what you want to do is the other way around, a hackish solution like this works fine:
<?php
function assign($val)
{
global $$val;
echo $$val;
}
$hello = "Some value";
assign('hello');
Ouputs: Some value
What you wish to do, PHP does not intend for. There is no conventional way to accomplish this. In fact, only quite extravagant solutions are available. One that remains as close to PHP as I can think of is creating a new class.
You could call it NamedVariable, or something, and as its constructor it takes the variable name and the value. You'd initiate it as $products = new NamedVariable('products', $productData); then use it as $this->view->assign($products);. Of course, your declaration line is now quite long, you're involving yet another - and quite obscure - class into your code base, and now the assign method has to know about NamedVariable to extract both the variable name and value.
As most other members have answered, you are better off suffering through this slight lack of syntactic sugar. Mind you, another approach would be to create a script that recognizes instances of assign()'s and rewrites the source code. This would now involve some extra step before you ran your code, though, and for PHP that's silly. You might even configure your IDE to automatically populate the assign()'s. Whatever you choose, PHP natively intends no solution.
This solution uses the GLOBALS variable. To solve scope issues, the variable is passed by reference, and the value modified to be unique.
function get_var_name(&$var, $scope=FALSE) {
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = 'unique'.rand().'value';
$vname = FALSE;
foreach ($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
$testvar = "name";
echo get_var_name($testvar); // "testvar"
function testfunction() {
$var_in_function = "variable value";
return get_var_name($var_in_function, get_defined_vars());
}
echo testfunction(); // "var_in_function"
class testclass {
public $testproperty;
public function __constructor() {
$this->testproperty = "property value";
}
}
$testobj = new testclass();
echo get_var_name($testobj->testproperty, $testobj); // "testproperty"