I've been given the task to remove undefined variable and undefined index errors, which i know how to
$value = isset($_POST['value']) ? $_POST['value'] : '';
The problem is this is way too time consuming, I predict over 2000 variables, $_GET, $_POST hasn't been set. So is there a regular expression i can use to set these variables quickly?
How do i do regex to change this $category = $_GET['c'] to this
$category = isset($_GET['c']) ? $_GET['c'] : ''?
And how do i do regex to change if($page or $category or $profile) to this
if(isset($page) or isset($category) or isset($profile))?
This is the best method i can think of by using regex find & replace in Notepad++. I assume over 2000 PHP variable/index undefined errors. How do i solve this without turning off errors?
you should not use regex because it's kind of heavy :)
if i'm understanding your question right, you can do this like this,
with this approach, it does not matter how many parameters contains POST or GET, you simply filter them through foreach loop and getting clean arrays with parameters, also you can make it a function that returning array.and then you just need to check if_array_key_exests() and do your things.
$_POST = ["user"=>"1", "num"=>2];
$_GET = ["user" => '', "num"=>1];
//function method
function filter($array)
{
$arr = array();
foreach ($array as $key => $val) {
if (!empty($val)) {
$arr[$key] = $val;
}
}
return $arr;
}
without function
$post = array();
foreach ($_POST as $key => $val) {
if (!empty($val)) {
$post[$key] = $val;
}
}
$get = array();
foreach ($_GET as $key => $val) {
if (!empty($val)) {
$get[$key] = $val;
}
}
For your first problem, replacing something like
(\$\w+)\s*=\s*\$_GET\[['"]?(\w+)['"]?\]\s*;
by
$1 = isset($_GET['$2']) ? $_GET['$2'] : '';
should work.
Regarding the second, I don't know if this is possible with a variable number of variables. This one works for 3 variables, replace
if\s*\(\s*\s*(\$\w+)\s+or\s+(\$\w+)\s+or\s+(\$\w+)\s*\)
by
if (isset($1) or isset($2) or isset($3))
You can add another \s+or\s+(\$\w+) before the last \s* in the search, and add another or isset($4) in the replacement for 4 variables etc.
I recommend you to replace them one by one instead of replacing all at once ;-)
Also note that if ($a) is not the same as if (isset($a)). Consider something like this:
// query string is a=0
$a = $_GET['a'];
if ($a) // will be false
if (isset($a)) // will be true
if (!empty($a)) // will be false
So, perhaps you want to use !empty() instead of isset(). This should work without notices, too.
resove first issue:
define a function like:
function global_get($key){
return isset($_GET[$key])?$_GET[$key]:'';
}
then use sed(linux tool) to replace all parts like this(it will modify all the $_GET[.*] of php extension files in your project,so be careful to use this):
find /yourproject -name "*.php" -exec sed -i "s/\$_GET\[\([^]]*\)\]/global_get(\1)/" \;
you may modify this command to apply your own demand.
The second issue could be harmful if you use the regex expression because it is hard to make a role rule.so I recommend you to replace manually.
Related
Hi so I want to know the easiest way to check if multiple POST parameters are set. Instead of doing a long if check with multiple "isset($_POST['example'])" linked together by "&&", I wanted to know if there was a cleaner way of doing it.
What I ended up doing was making an array and looping over it:
$params_needed = ["song_name", "artist_name", "song_release_date",
"song_genre", "song_medium"];
I would then call the function below, passing in $params_needed to check if the parameter names above are set:
function all_params_valid($params_needed) {
foreach ($params_needed as $param) {
if (!isset($_POST[$param])) {
error("Missing the " . $param . " variable in POST request.");
return false;
}
}
return true;
}
if (all_params_valid($params_needed)) {
$song_name = $_POST["song_name"];
$artist_name = $_POST["artist_name"];
$song_release_date = $_POST["song_release_date"];
$song_genre = $_POST["song_genre"];
$song_medium = $_POST["song_medium"];
...
}
However when I do this, it gets stuck on the first index and says "Missing the song_name variable..." despite actually including it in the POST request, and I'm not sure why this is happening. The expected behavior would be for it to move on and tell me the next parameter "artist_name" is not set, but this doesn't happen.
I personally like using array_diff for this issue.
PHP array_diff documentation
What you care about is your expected input is the same as the given input.
So you can use array_diff like this:
$params_needed = ["song_name", "artist_name", "song_release_date",
"song_genre", "song_medium"];
$given_params = array_keys($_POST);
$missing_params = array_diff($params_needed, $given_params);
if(!empty($missing_params)) {
// uh oh, someone didn't complete the form completely...
}
How I approach this is by using array_map() so I can return all the values in the array whilst checking if it isset()
PHP 5.6 >
$args = array_map(function($key) {
return isset($_POST[$key]) ? array($key => $_POST[$key]) : someErrorMethod($key);
}, ["song_name", "artist_name", "song_release_date", "song_genre", "song_medium"]);
PHP 7+
$args = array_map(function($key) {
return array($key => $_POST[$key] ?? someErrorMethod($key));
}, ["song_name", "artist_name", "song_release_date", "song_genre", "song_medium"]);
Your error method could look something like this:
function someErrorMethod($key) { die("$key cannot be empty."); }
Inside of your $args variable, you will have an array of key => value. For example,
echo $args['song_name'];
I'm trying to define three empty variables through a foreach loop to make my code cleaner. This is what I've tried, however I see the error:
Notice: Undefined variable: hi
foreach(['$hi','$bye','$hello'] as $key) {
$key = "";
}
$hi .= "hello";
When I remove the foreach loop and simply define each empty variable one by one, like this, it works:
$hi = "";
$bye = "";
$hello = "";
You're assigning to $key, not to the variable that's named by it. To indirect through a variable, you need to use $$key. But the value of the variable shouldn't include the $, just the variable name.
foreach (['hi', 'bye', 'hello'] as $key) {
$$key = "";
}
$hi .= "hello";
However, if you ever find yourself using variable variables like this, you're almost certainly doing something wrong. You should probably be using an associative array instead.
You have strings which are saved in $key. So the value of $key is a string and you set it to "".
Later you want to append something to a variable you never used.
Try to remove the ' and write
foreach([$hi, $bye, $hello] as $key) {
Generally thats not the best way to initialise multiple variables. Try this
Initializing Multiple PHP Variables Simultaneously
Easier way:
list($hi, $bye, $hello) = "";
foreach creates a new array variable in memory, so you only clear these values inside the array in memory which is useless out of the foreach sentence. the best way is:
$h1=$bye=$hello="";
I didn't think that a foreach process will work more fast than a Simple equal (=), foreach function uses more CPU resources than a simple =. That's because the math CPU exists.
This question already has answers here:
Invalid argument supplied for foreach()
(20 answers)
Closed 7 years ago.
Not a major problem but I was wondering if there is a cleaner way to do this. It would be good to avoid nesting my code with an unnecessary if statement. If $items is empty php throws an error.
$items = array('a','b','c');
if(!empty($items)) { // <-Remove this if statement
foreach($items as $item) {
print $item;
}
}
I could probably just use the '#' error suppressor, but that would be a bit hacky.
There are a million ways to do this.
The first one would be to go ahead and run the array through foreach anyway, assuming you do have an array.
In other cases this is what you might need:
foreach ((array) $items as $item) {
print $item;
}
Note: to all the people complaining about typecast, please note that the OP asked cleanest way to skip a foreach if array is empty (emphasis is mine). A value of true, false, numbers or strings is not considered empty.
In addition, this would work with objects implementing \Traversable, whereas is_array wouldn't work.
The best way is to initialize every bloody variable before use.
It will not only solve this silly "problem" but also save you a ton of real headaches.
So, introducing $items as $items = array(); is what you really wanted.
$items = array('a','b','c');
if(is_array($items)) {
foreach($items as $item) {
print $item;
}
}
If variable you need could be boolean false - eg. when no records are returned from database or array - when records are returned, you can do following:
foreach (($result ? $result : array()) as $item)
echo $item;
Approach with cast((Array)$result) produces an array of count 1 when variable is boolean false which isn't what you probably want.
I wouldn't recommend suppressing the warning output. I would, however, recommend using is_array instead of !empty. If $items happens to be a nonzero scalar, then the foreach will still error out if you use !empty.
I think the best approach here is to plan your code so that $items is always an array. The easiest solution is to initialize it at the top of your code with $items=array(). This way it will represent empty array even if you don't assign any value to it.
All other solutions are quite dirty hacks to me.
foreach((array)$items as $item) {}
i've got the following function in my "standard library"
/// Convert argument to an array.
function a($a = null) {
if(is_null($a))
return array();
if(is_array($a))
return $a;
if(is_object($a))
return (array) $a;
return $_ = func_get_args();
}
Basically, this does nothing with arrays/objects and convert other types to arrays. This is extremely handy to use with foreach statements and array functions
foreach(a($whatever) as $item)....
$foo = array_map(a($array_or_string)....
etc
Ternary logic gets it down to one line with no errors. This solves the issue of improperly cast variables and undefined variables.
foreach (is_array($Items) || is_object($Items) ? $Items : array() as $Item) {
It is a bit of a pain to write, but is the safest way to handle it.
You can check whether $items is actually an array and whether it contains any items:
if(is_array($items) && count($items) > 0)
{
foreach($items as $item) { }
}
Best practice is to define variable as an array at the very top of your code.
foreach((array)$myArr as $oneItem) { .. }
will also work but you will duplicate this (array) conversion everytime you need to loop through the array.
since it's important not to duplicate even a word of your code, you do better to define it as an empty array at top.
This is a minor thing, but it's been bugging me for a while. I've wracked my brain for a way to write statements like this without any repetition of code. For example:
echo isset($array[0])? $array[0]: 'not set';
$var = empty($other_var)? '$other_var not set': $other_var;
Is there some sort of test-and-return (for the former) or test-and-set (for the latter) operator I don't know about? This may seem like a minor point, but the duplication seems unnecessary and can lead to very long lines that can complicate maintenance. Consider:
$another_var = array_key_exists($array[Utility::FindIndex($username)][Constants::App_CRITERION], $haystack[NthDimension('my dimensional indicator')])? $array[Utility::FindIndex($username)][Constants::App_CRITERION], $haystack[NthDimension('my dimensional indicator')]: 'not set';
Yes, yes, the above line is totally contrived but it's not unthinkable that something like this could occur. It just seems strange to me that there isn't a way to test something and assign it's value (if true) without repetition without repetition.
It won't handle the isset () case, which is a main use case for this pattern, but PHP 5.3 does have a short form for the ternary operator.
$new_val = $if_true ? $if_true : $if_false;
can be shortened to
$new_val = $if_true ?: $if_false;
I couldn't find it in the docs, strangely, but here's a question about it: What is ?: in PHP 5.3?
I think in PHP 6 there was a function planned called issetor or something similar. But I can't remember the name. And PHP 6 is dead either way.
So, write it yourself:
function issetor(&$var, $default) {
return isset($var) ? $var : $default;
}
echo issetor($_GET['me'], 'you');
If you want to make it even more abstract, look at this:
function isor(&$var, $default, $condition) {
if (!is_callable($condition)) {
throw new InvalidArgumentExpression('condition not callable!');
}
return $condition($var) ? $var : $default;
}
// this is equivalent to issetor($_GET['me'], 'you');
echo isor($_GET['me'], 'you', function(&$var) { return isset($var); });
// but you may use a more complicated thing here, too:
echo isor($_GET['me'], 'you', function($var) use($allowed) { return in_array($var, $allowed); });
// this is equivalent to:
echo in_array($_GET['me'], $allowed) ? $_GET['me'] : 'you';
// now the "normal" version is still shorter. But using isor allows you to store often used $condition closures in variables. For example, if you want to check if several values are in an array, you could write:
$isAllowed = function ($var) use ($allowed) {
return in_array($var, $allowed);
};
$a = isor($a, 'default', $inAllowed);
$b = isor($b, 'default', $inAllowed);
$c = isor($c, 'default', $inAllowed);
$d = isor($d, 'default', $inAllowed);
If you want to pass additional variables to your condition function without always useing closures you may add another argument. (Note I didn't use an argument array and call_user_func_array, because you may not pass per reference using it, but obviously you may extend the code so it does so.)
function isor(&$var, $default, $condition, $addArgument = null) {
if (!is_callable($condition)) {
throw new InvalidArgumentExpression('condition not callable!');
}
return $condition($var, $addArgument) ? $var : $default;
}
// the above in_array condition:
echo isor($a, 'default', 'in_array', $allowed);
There's got to be a much more elegant way of doing this.
How do I convert all non-empty post data to session variables, without specifying each one line by line? Basically, I want to perform the function below for all instances of X that exist in the POST array.
if (!empty($_POST['X'])) $_SESSION['X']=$_POST['X'];
I was going to do it one by one, but then I figured there must be a much more elegant solution
I would specify a dictionary of POST names that are acceptable.
$accepted = array('foo', 'bar', 'baz');
foreach ( $_POST as $foo=>$bar ) {
if ( in_array( $foo, $accepted ) && !empty($bar) ) {
$_SESSION[$foo] = $bar;
}
}
Or something to that effect. I would not use empty because it treats 0 as empty.
The syntax error, is just because there is a bracket still open. it should be
$vars = array('name', 'age', 'location');
foreach ($vars as $v) {
if (isset($_POST[$v])) {
$_SESSION[$v] = $_POST[$v];
}
}
It should work like that. If you use
if ($_POST[$v])...
it strips down empty data.
Here you go,
if(isset($_POST) {
foreach ($_POST as $key => $val) {
if($val != "Submit")
$_SESSION["$key"] = $val;
}
}
Well the first thing I would suggest is you don't do this. It's a huge potential security hole. Let's say you rely on a session variable of username and/or usertype (very common). Someone can just post over those details. You should be taking a white list approach by only copying approved values from $_POST to $_SESSION ie:
$vars = array('name', 'age', 'location');
foreach ($vars as $v) {
if (isset($_POST[$v]) {
$_SESSION[$v] = $_POST[$v];
}
}
How you define "empty" determines what kind of check you do. The above code uses isset(). You could also do if ($_POST[$v]) ... if you don't want to write empty strings or the number 0.
This lead me to this bit, which is a simplified version of #meder's answer:
<?php
$accepted = array('foo', 'bar', 'baz');
foreach ( $accepted as $name ) {
if ( isset( $_POST[$name] ) ) {
$_SESSION[$name] = $_POST[$name];
}
}
You might also substitute !empty() for isset() above, though be aware of how much farther-reaching empty() is, as #meder pointed out.
$_SESSION["data"] = $POST;
$var = $_SESSION["data"];
Then just use $var as a post variable. For example:
echo $var["email"];
instead of
echo $_POST["email"];
Cheers