6

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.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Run
  • 54,938
  • 169
  • 450
  • 748

9 Answers9

21

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.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • +1 for the `array_merge`.. good thinking, that's a much cleaner way to do this – Jon Gauthier Mar 22 '11 at 02:14
  • 1
    This could even be shortened to `$values = $_POST + array('pg_title' => null, …)`. – deceze Mar 22 '11 at 02:18
  • @deceze: thanks. still can't my head around with this suggestion. I still get empty space in my db injection when there is no data there... – Run Mar 22 '11 at 02:25
  • Oh, cool, I didn't know PHP supported `array + array` logic. Good to know. – Jon Gauthier Mar 22 '11 at 02:25
  • @lau What this does, and what you're doing as well, only in a much more cumbersome way, is to establish default values (`null`) for your variables, something you should always do. My method just does it all in one batch using array operations, instead of doing it one by one for individual variables. The end result is identical to what you're doing though. What that has to do with your DB insertion I don't know, since you haven't provided any details on that. – deceze Mar 22 '11 at 02:29
  • @deceze: thanks. I just updated my post above. but I am thinking to use an user defined function or the `filter_var` which seems to be a cool function. the only thing is I'm still not sure how to use `filter_var`. – Run Mar 22 '11 at 02:40
  • @lau So what do you expect in the DB instead? You want the `null` value? Or you want to skip the value completely? – deceze Mar 22 '11 at 02:42
  • @deceze: I think I want skip the value completely so that I get a _NULL_ in that column but not the value string of NULL. does it make sense? – Run Mar 22 '11 at 02:47
  • @lau If your DB access library maps PHP's `null` to MySQL's `NULL`, then something like my updated answer should satisfy you. If you want to skip the field completely, you will need to dynamically construct your queries, which is an entirely different topic... – deceze Mar 22 '11 at 02:51
5

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');
Jacob
  • 8,278
  • 1
  • 23
  • 29
  • 1
    No application should ever use `isset() && !empty()` for any reason. https://stackoverflow.com/a/4559976/2943403 – mickmackusa Aug 11 '21 at 23:01
5

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.

Jon Gauthier
  • 25,202
  • 6
  • 63
  • 69
2

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.

Jon
  • 428,835
  • 81
  • 738
  • 806
1

+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.

vladkras
  • 16,483
  • 4
  • 45
  • 55
0

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.

0

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.

Charles
  • 50,943
  • 13
  • 104
  • 142
-1

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;
revoke
  • 529
  • 4
  • 9
  • You can't reference the key 'id' if it doesn't exist. It will throw an error. So is($_GET['id']) will fail in this case. Of course this depends on the error level you have set. – unflores Jun 03 '13 at 13:18
  • @unflores Actually, passing the parameter by reference implicitly creates it, without emitting a notice. – Brilliand Feb 10 '14 at 16:20
-1

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.

mario
  • 144,265
  • 20
  • 237
  • 291
  • @ is a blanket "ignore warnings" - a bit excessive when we just want to get around a particular warning. – Brilliand Feb 08 '14 at 00:06
  • Context is key. If silent substitution fits the bill, `isset` suffices. With `@` you can still uncover notices later. – mario Feb 08 '14 at 00:09