I wonder if there any better ideas to solve the problem below,
I have a form with a number of input fields, such as,
<input name="pg_title" type="text" value="" />
<input name="pg_subtitle" type="text" value="" />
<input name="pg_description" type="text" value="" />
<input name="pg_backdate" type="text" value="" />
etc
But sometimes don't need certain input fields above in my form, for instance, I only need the page title for my db injection,
<input name="pg_title" type="text" value="" />
etc
And I have another php page to handle the $_POST data,
$pg_title = null;
$pg_subtitle = null;
$pg_description = null;
$pg_backdate = null;
if(isset($_POST['pg_title']) && !empty($_POST['pg_title']) ) $pg_title = $_POST['pg_title'];
if(isset($_POST['pg_subtitle']) && !empty($_POST['pg_subtitle']) ) $pg_subtitle = $_POST['pg_subtitle'];
if(isset($_POST['pg_description']) && !empty($_POST['pg_description']) ) $pg_description = $_POST['pg_description'];
if(isset($_POST['pg_backdate']) && !empty($_POST['pg_backdate']) ) $pg_backdate = $_POST['pg_backdate'];
Every time I will have to check if the $_POST of a certain input field is set and not empty, otherwise its variable will be set to null, so that I won't inject an empty space into my DB.
I find the isset and !empty in the if-condition are very repetitive when I have a long list of variables to handle.
Is there any default PHP function to 'shorten' the process above? Or do I have to write a user-defined function to handle this?
Or maybe there is another way to do this?
Just some extra code in my php page that handle the $_POST data,
$sql = "
UPDATE root_pages
SET
pg_url = ?,
pg_title = ?,
pg_subtitle = ?,
pg_backdate = ?,
pg_description = ?,
...
updated_by = ?
WHERE pg_id = ?
";
$result = $connection->run_query($sql,array(
$pg_url,
$pg_title,
$pg_subtitle,
$pg_backdate,
$pg_description,
...
$pg_id
));
as you see that $pg_subtitle, $pg_backdate, $pg_description, etc always present in my query. so if I get $pg_subtitle = '' instead of $pg_subtitle = null when there is no data in it, my db record will have an empty space for that column.
isset && !empty is redundant. The empty language construct is basically shorthand for !isset($foo) || !$foo, with !empty being equivalent to isset($foo) && $foo. So you can shorten your code by leaving out the isset check.
A much simpler way is:
$values = array('pg_title' => null, 'pg_subtitle' => null, …);
$values = array_merge($values, $_POST);
// use $values['pg_title'] etc.
If you don't want your default null values to be overwritten by falsey values, e.g. '', you can do something like this:
$values = array_merge($values, array_filter($_POST));
Just be aware that '0' is falsey as well.
You can use a simple function
function post_value_or($key, $default = NULL) {
return isset($_POST[$key]) && !empty($_POST[$key]) ? $_POST[$key] : $default;
}
Then use:
$pg_title = post_value_or('pg_title');
// OR with a default
$pg_title = post_value_or('pg_title', 'No Title');
empty($var) is an abbreviation for !( isset($var) && $var ).
So !empty($_POST['...']) will be sufficient for your situation — the isset call you have currently is redundant.
User-defined function, I 'm afraid. But they come out short enough. I have one lying around somewhere if you want to take a look, but it's really trivial as you can imagine.
Update:
Here's one I found:
define('PARAM_INT', 0);
define('PARAM_STR', 1);
function get_param($name, $default = null, $type = PARAM_INT) {
$value = $default;
if (isset($_POST[$name])) {
$value = $_POST[$name];
}
else if (isset($_GET[$name])) {
$value = $_GET[$name];
}
switch($type) {
case PARAM_INT:
$value = (int)$value;
break;
case PARAM_STR:
break;
default:
// error your heart out here
}
return $value;
}
Of course now all the cool kids do it with filter_var, but the idea is the same.
+1 for array_merge() but I think that nevertheless short form for:
if (isset($_POST['some_var']) and !empty($_POST['some_var'])) $some_var = $_POST['some_var'];
else $some_var = NULL;
should be:
$some_var = $_POST['some_var'] ? $_POST['some_var'] : NULL;
yes, it causes "undefined index" notice, but it checks for both existance and emptiness
EDIT: and returns NULL of course, as OP asked.
During a small research, I've found an interesting "Control Flow Function" for this case, I've never used before: NULLIF()
So you can perform this task without PHP. Just wrap all variables in it:
NULLIF('".$_REQUEST['some_var']."', '')
in your query instead of '".$_REQUEST['some_var']."'
If variable is empty or doesn't exist it will be NULLIF('', '') as far as '' == '' it will return NULL. Otherwise it will return first arg == your variable.
Consider using the available-by-default filter extension's filter_input function. You'll avoid the missing index Notice and get data sanitization at the same time.
I do not have enough rep to comment. However, the suggestion that vladkras made to use:
$some_var = $_POST['some_var'] ? $_POST['some_var'] : NULL;
is not E_ALL compliant. You should be checking array keys before accessing them using either empty() or isset() as others have suggested. Especially for user input.
Also, his second suggestion to use the MySQL function "NULLIF()" as in the following manner:
NULLIF('".$_REQUEST['some_var']."', '')
is even worse. Inserting unsanitized user input directly into a SQL query is a primary vector for a SQL injection attack.
I'm always making myself unpoular with that. But the best approach is to get over the micro optimization mantra and use the syntax construct which was devised for that #.
Factually I'm lying. I'm all too often using isset() myself. (But at least I know it's not very bright.)
And for new projects I'm now using object-oriented superglobals, which combine filtering and implicit isset tests into $_POST, $_GET, $_REQUEST wrappers. $_REQUEST->ascii["title"] or $_GET["raw"] don't bring up debug messages anymore.
This function check if variable is set, is not empty, eventually if has any value.
/**
* #param var - testing variable
* #param value
* #return boolean
*/
function is(&$var, $value = null){
if(!is_null($value)){ return IsSet($var) && $var == $value; }
return IsSet($var) && !empty($var);
}
echo $_GET['id']; // this produce Warning
echo is($_GET['id'])?'1':'0'; // return false
echo $_GET['id']; // after first using function is(), will not be produce Warning!!!
is($_GET['id']); // return false
IsSet($_GET['id']); // return false
$_GET['id'] = 7;
is($_GET['id'], 7); // return true;
Related
I'm looking at a way of structuring if clauses using the DRY principles of Don't Repeat Yourself.
This is work involving scripts that are ~15 years old and poorly coded with globals etc., and I'm asked to drag this script/site into the 21st Century - but due to time and cost constraints, I can not facilitate a complete site rewrite from scratch, although I know that would be far better.
I have a value that is formerly a global value and I do not know where it comes from and it may come from different places from different pages.
I have some activity that is checking an input value in $_POST or $_GET data, if the input value is empty (or invalid), then check if the value is in fact sat in a $_SESSION. If the input value is still empty (or invalid) then boot to another page.
My code as it stands:
$userId = $_REQUEST['userid'];
if (empty($userId)) {
$userId = $_SESSION['userid'];
}
if(empty($userId) || !is_numeric($userId))
{
header("Location:contactdetails.php");
die();
}
I repeat the empty() function twice, I could wrap both IF's into one line but then would need an IF to pass the value from the REQUEST or the SESSION into the $userId variable.
Is there a (better) way that I can check the two possible inputs to see where this [formerly global] '['userid']' variable is coming from and applying that value to the page-local userId variable?
You can use the ternary operator. The first expression will be used if it evaluates to true, otherwise the latter one. The $_REQUEST superglobal takes precedence in this case, like the code in the question:
$userId = $_REQUEST['userid'] ?: $_SESSION['userid'];
if (empty($userId) || !is_numeric($userId)) {
header("Location:contactdetails.php");
exit;
}
However as Havenard stated in a comment above, blindly trusting request data could be a security issue.
Also note that the condition will be true if any user IDs are 0, in that case a null check would be better:
$userId = $_REQUEST['userid'] ?: $_SESSION['userid'];
if ($userId === null || !is_numeric($userId)) {
header("Location:contactdetails.php");
exit;
}
Of course this is assuming that you do not store falsy values in the $_SESSION as a non-null value.
If $_SESSION['userid'] is guaranteed to be set, rink.attendant.6's answer seem like a clean approach. Otherwise, you will have to perform the necessary checks for both $_REQUEST and $_SESSION to guarantee that $userId is set properly:
if (isset($_REQUEST['userid']) && is_numeric($_REQUEST['userid']))
$userId = $_REQUEST['userid'];
else if (isset($_SESSION['userid']) && is_numeric($_SESSION['userid']))
$userId = $_SESSION['userid'];
else // no acceptable value for $userId in sight
{
header("Location: contactdetails.php");
exit;
}
You might want to reconsider using is_numeric() also, since it validates as true for numeric representations in any format, not just positive integers as you might expect.
There are two different problems you're solving here. First is the problem of defaulting and second is filtering. Take each in turn.
For defaulting, you can implement a simple "get from array if it exists otherwise default" helper:
function array_get(array $a, $key, $default = null) {
return (array_key_exists($key, $a) ? $a[$key] : $default);
}
You can then use this helper to provide default chaining:
$userId = array_get($_REQUEST, 'userid', $_SESSION['userid']);
For filtering, you know from this chain that you've got either a null or a value from one of the two arrays. Since you're looking for ostensibly a database ID, I like a function like this:
function is_id_like($it) {
$rc = filter_var($it, FILTER_VALIDATE_INT, array ('options' => array (
'default' => false, 'min_range' => 1,
)));
return (false === $rc ? false : true);
}
This ensures that the number you give it looks like an int, is 1 or higher, and will return false if not. So all these pass: 1, "1", and "1.0" but these all fail: 0 and "1.1".
Combining these, and allowing for the session to not have a user ID:
$userId = array_get($_REQUEST, 'userid', array_get($_SESSION, 'userid'));
if (! is_id_like($userId)) {
header('Location: contactdetails.php');
die();
}
The total number of checks has changed to one array_key_exists and one filter_var, but the code is substantially more readable and these methods can be reused throughout your code base.
If the value will only ever be set in either the request or session then concat the possible values and validate once.
You should be using if-else for two-way statements and using a switch for n-way statements.
swicth($myVar){
case 1: doX();break;
case 'a': doY();break;
case 2: doZ();break;
default: doA();
}
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');
?>
my code:
if (isset($dayMarks[$res['resId']][$dDate])) {
$var=$dayMarks[$res['resId']][$dDate];
echo $var;
}
note that the isset condition is identical to the value assigned to $var, which creates a pretty ugly code.
How is it possible to assign the condition to $var without repeating it?
(in javascript, I'd write if (var=$dayMarks[$re...) )
This is a common problem in PHP where including files can create uncertainty about variables.
There are a two approaches that work well for me.
Default Assignment
With default assignment the $var variable will be given a default value when the key doesn't exist.
$var = isset($dayMarks[$res['resId']][$dDate]) ? $dayMarks[$res['resId']][$dDate] : false;
After this code can assume that $var will always contain a valid value.
Default Merger
My preferred method is to always declare a default array that contains all the required values, and their defaults. Using the False value to mark any keys that might be missing a value (assuming that key holds another value type besides boolean).
$default = array(
'date'=>false,
'name'=>'John Doe'
);
$dayMarks[$res['resId']] = array_merge($default, $dayMarks[$res['resId']]);
This will ensure that the required keys for that variable exist, and hold at least a default value.
You can now test if the date exists.
if($dayMarks[$res['resId']]['date'] !== false)
{
// has a date value
}
While this might not work exactly for your array. Since it looks like it's a table structure. There is a benefit to switching to named key/value pairs. As this allows you to easily assign default values to that array.
EDIT:
The actual question was if it was possible to reproduce the JavaScript code.
if (var=$dayMarks[$re...)
Yes, this can be done by using a helper function.
NOTE: This trick should only be used on non-boolean types.
function _isset($arr,$key)
{
return isset($arr[$key]) ? $arr[$key] : false;
}
$a = array('zzzz'=>'hello');
if(($b = _isset($a,'test')) !== false)
{
echo $b;
}
if(($c = _isset($a,'zzzz')) !== false)
{
echo $c;
}
See above code here
$isset = isset(...); //save the value
if ($isset) { .... }; // reuse the value
...
if ($isset) { ... }; // reuse it yet again
The only thing you can do is store $res['resId'][$dDate].
$var = $res['resId'][$dDate];
if( isset($dayMarks[$var]) ) {
$var = $dayMarks[$var];
echo $var;
}
If you only want to assign a variable processing simply, you can also write this as:
$var = $dayMarks[$res['resId']][$dDate]);
if (!isset($var)) unset($var);
I am getting tried of if isset($_GET['whatever'])... before the rest of my if statement. E_NOTICE errors are way to handy to turn off and for $_POST variables I have a solution in my init script..
$POST = (is_array( $_POST ) && count( $_POST ) > 0);
I find this helps self posting scripts look clean.
if ($POST) {
// now do something with $_POST...
}
I'm not sure how to dynamically do this if you have no idea what the key is? Can anyone help find a similar solution for $_GET variables?
EDIT:
I simply want if ($_GET['whatever'] == "whatever"); to return false if it's not set and no E_NOTICE errors.
EDIT:
Sorry if I'm unclear I'm looking for a solution for $_GET not $_POST--I only am using $_POST as an example of what I hope to achieve.
Sometimes I use a global GET function:
function GET($key, $default = null) {
return isset($_GET[$key]) ? $_GET[$key] : $default;
}
The main idea of all that mess is simple: every variable in your program should be initialized before use.
Thus, the best you can do is to set all variables centralized, say, at the very top of your script.
But there are some different cases. For the case you posted, you need none of these but
if ($_SERVER['REQUEST_METHOD'] == "POST")
Already answered, but since it wasn't mentioned, also try:
$var = filter_input(INPUT_GET, 'varname');
That will return null if it doesn't exist, without the annoying array notices, and also filters out potential bad stuff in various ways. See also: http://www.php.net/filter
You can make a function to do this for you.
function getVar($item){
return isset($_GET[$item]) ? $_GET[$item] : '';
}
Then you can do if(getVar('whatever') == "whatever").
Here are two methods.
/*
* Makes any request keys into variables of the same name
*/
foreach($_GET AS $key => $value) {
${$key} = ($value);
}
//Assuming a input key of $_GET['whatever']
echo $whatever;
/*
* Casting to an object
*/
$get = (object) $_GET;
//Assuming a input key of $_GET['whatever']
echo $get->whatever
A third option that I can think of is making the $_GET into its own class. PHP overloading is handy trick for doing this.
http://php.net/manual/en/language.oop5.overloading.php
I didn't feel like writing up an example demonstrating this. :)
simple I think you want to check if get value is set then need to do the next step otherwise do different
I like the first answer but need to check thats if it works for you
if(isset($_GET['whatever']){
if ($_GET['whatever'] == "whatever");{
//do the rest
}
else{
//do the rest
}
}
hope it may help if what I think is your need
short
no notice
$key = &$_POST['key'];
This way (inside function) it is depracted, and shows error:
function f($s){}
f(&$_POST['key']);
Fatal error: Call-time pass-by-reference has been removed
When writing these sorts of scripts, I usually do something like this at the top:
$submitted = isset($_POST['submit']) ? true : false;
$username = isset($_POST['username']) ? $_POST['username'] : null;
$password = isset($_POST['password']) ? $_POST['password'] : null;
(etc.)
Then, when testing the values, it looks something like this:
if ($submitted)
{
if ($username && $password)
{
// do stuff with username and password including testing their values
}
}
It seems to work pretty well for me.
My error logs get huge quick because I reference a ton of variables with may or may not exist. I have been going back through and starting to clean them up but wanted to see if there was a more effective (and cleaner) way of checking for php variables.
Currently I use as the following:
Example 1:
<?php
if (isset($_SESSION['checked']) && $_SESSION['checked'] == "Y") {
do something;
}
?>
Example 2:
(within html form)
<input type="text" name="sample_number" onKeyUp="this.value=this.value.replace(/[^0-9]/ig, '')" value="<?php echo $fields['sample_number']; ?>" />
where sample number is displayed if it is set.
is there a better way to handle scenarios like these?
It's a little more verbose, but array_key_exists() is faster than isset() for checking array key presence, and isset() comes with the caveat that it will return false for NULL values (you may have intentionally set a variable to NULL, but isset() will be semantically wrong in that case).
So, in your first example:
<?php
if(array_key_exists('checked', $_SESSION) && $_SESSION['checked'] == 'Y') {
do something;
}
?>
In your second example, I suggest using array_key_exists() and the ternary operator:
<input type="text" name="sample_number" onKeyUp="this.value=this.value.replace(/[^0-9]/ig, '')" value="<?= array_key_exists('sample_number', $fields) ? $fields['sample_number'] : '' ?>" />
as it makes for a more compact solution without repeating your HTML through if() conditions.
Edit: I always like to initialize my variables at the earliest possible point, FWIW. This can get tricky as there's always the potential overhead if, say, you had a slew of arrays you initialized but then didn't end up using them (eg, if they were only used in certain conditions), but then again everything's relative to your application. There's no substitute for good judgment.
I usually write myself some function that gets me the values out of the related array (being it session, get or post). I usually make these function assign a default value, as I don't really care if a value is set or the default value is set (which leads to no special behaviour).
Essentially, a function could look like this:
function getSessionVar ( $name, $default = '' )
{
if ( !isset( $_SESSION[$name] )
return $default;
switch ( gettype( $default ) )
{
'integer':
return intval( $_SESSION[$name] );
break;
'double':
return floatval( $_SESSION[$name] );
break;
default:
return $_SESSION[$name];
}
}
Then I just use this function at the beginning of a file/code block to get all variables I'm interested in and just work with the value of that variable.
isset is the method that they teach in Zend certification training. You could take shortcuts and do the # in front of the statement that's barking, or you could just turn the error level down, but I'm a firm believer that errors exist for a reason....well, most of them anyways. Take your time and do it right.
It's not the best way around it, but if you badly need to report all errors but still wanna ignore the case you described up there, I guess you could do:
if ($test = #$_SESSION['checked'] && $test == 'Y') {
do something
}