Should escapeshellarg
or escapeshellcmd
be used for the host? I've read both of the man pages just now, and they offer conflicting advice. I'm about 99% sure that escapeshellarg
should be used with the host though:
$host = shellescapearg("google.com");
exec("ping {$host}");
As Christian Sciberras began saying in his comment:
I would validate the url before escaping it instead of afterwards. I can't imagine that an escaped one would ever pass when a non-escaped one would not; however, when you escape it and then check it, you're not really validating what was inputted, but rather you're validating a processed version of it.
Imagine this scenario: You have user profiles, and they allow users to enter a description of themselves. Now, these may have some HTML entities in them, such as &
or <
. Now, when you store this, you're going to store the original version. When you display it back to the browser, you will pass it through something like htmlentities()
. My point is, when you let the user update their profile, you're going to validate the original version with &
instead of &
.
Christian's (and my) feelings on the host validation are along those same lines. When you validate user input, you want to validate the actual input, not the processed version.
But also to add something:
You should never assume that array keys exist in the $_GET
/$_POST
/$_COOKIES
, so on arrays (any user-dependent array).
For example:
$userinput = $_GET['host'];
If the user just goes to mypage.php
without the host param, then PHP will throw a notice when your script tries to access a non-existent array key.
Another case where users can trigger errors messages is something like:
mypage.php?host[]=blah
That means that $_GET['host']
is array('blah')
. So, when you try to pass that into escapeshellcmd
or explode
, it will throw an error about expecting a string and getting an array.
What I typically do is something like:
if(isset($_GET['blah']) && is_string($_GET['blah'])) {
$blah = $_GET['blah'];
} else {
$blah = null;
}
Or, the shorter version I usually use:
$blah = (isset($_GET['blah']) && is_string($_GET['blah'])) ? $_GET['blah'] : null;
Note though that isset()
is not the same as array_key_exists
, which sometimes makes more sense. Also, you can always use is_string
because input arrays will always contain string values, even if the user's input is numeric. (The exception is, if the user inputs an array, it does become an array.)