I was basically playing around with OOP and was creating a way to validate and sanitise input when I started to run into problems sanitising and then performing further validation. What I'm looking for is to take the posted $_POST['name'] data, sanitise the input to remove any numbers and validate that the data left is neither null or numeric characters.
But I cant get the sanitised input saved to $sanitised, It seems to be empty, but when I replace
$sanitised=$fv->noNumbers($_POST['name']);
with
$sanitised=preg_replace('/[0-9]/', '', $_POST['name']);
everything works fine, so I think I'm messing up something in this $sanitised variable.
I wanna learn so either a solution to this or a "you're an idiot and doing it all wrong" would be much appreciated.
<?php
class formSanitise {
public function noNumbers($value) {
$value = preg_replace('/[0-9]/', '', $value);
}
public function isEmpty($value) {
return (!isset($value) || trim($value) == '') ? true : false;
}
public function isAlpha($value) {
return preg_match('/[^a-z]/i', $value) ? false : true;
}
?>
processor.php
<?php
include('class.formSanitise.php');
$fv = new formSanitise();
$sanitised= $fv->noNumbers($_POST['name']);
if ($fv->isEmpty($sanitised)) {
$fv->addError('Name', 'Please enter something');
}
if (!$fv->isAlpha($sanitised)) {
$fv->addError('Name', 'Please enter your name');
}
?>
You'll either need to create a return in noNumbers or pass $value by reference.
Return method:
public function noNumbers($value) {
return preg_replace('/[0-9]/', '', $value);
}
Reference
public function noNumbers(&$value) {
$value = preg_replace('/[0-9]/', '', $value);
}
returning a value means that $value is an entirely different variable, and will be assigned to $sanitized when it's returned from the function. Passing by reference means that $value is the exact same variable as the one you passed to noNumbers and as such, anything that happens to the variable inside the function will happen to the variable that has been passed in.
In the above code snippet the function noNumbers does not return any value.The argument passed to the function has a scope within that function only and in order to make that value available to calling function there must be a return statement within function which will return the value to the calling function .Alternatively you can pass the value to function by reference .
Related
function valueFromGetOrPost($parameter)
{
$shvalue=NULL;
if ($_GET[$parameter])
{
$shvalue=$_GET[$parameter];
}
else if (isset($_POST[$parameter]))
{
$shvalue=$_POST[$parameter];
}
return $shvalue;
}
say by using filter_input
Basically the code check whether a parameter exist either in GET or POST. And then return the value of the parameter.
I think this must be so common it should be there by some built in function already
Use $_REQUEST (documentation).
An associative array that by default contains the contents of $_GET, $_POST and $_COOKIE.
So your code will look like:
function valueFromGetOrPost($parameter)
{
$shvalue=NULL;
if ($_REQUEST[$parameter])
{
$shvalue=$_REQUEST[$parameter];
}
return $shvalue;
}
You could use fast return to simplify it a bit, i.e
function valueFromGetOrPost($parameter){
$shvalue=NULL;
if (isset($_GET[$parameter])){
return $_GET[$parameter];
} else if (isset($_POST[$parameter])){
return $_POST[$parameter];
}
}
Or, you could use a ternary operator, since you're returning NULL anyway if neither are set:
function valueFromGetOrPost($parameter){
$shvalue = (isset($_GET[$parameter]) ? $_GET[$parameter] : $_POST[$parameter]);
return $shvalue;
}
Here is my proposal, using the filter_input() function:
function valueFromGetOrPost($parameter)
{
$value = ($getValue = filter_input(INPUT_GET, $parameter))
? $getValue
: filter_input(INPUT_POST, $parameter);
return ($value) ? $value : NULL;
}
I am having trouble using a variable generated in one function, as a variable in a second function.
The Problem:
I get Notice: Undefined variable: parameter in the validate function, on the line:
$this->$methodName($item,$value,$parameter) OR $valid=false;
When the function call for splitRulesAndParameters is simply replaced with the code within the function, the problem goes away.
The Scenario:
The following two functions are both within the Validator class, the first, validate, makes use of the second, splitRulesAndParameters
Here is the validate function:
public function validate($data, $rules)
{
$valid= true;
foreach($rules as $item=>$ruleSet)
{
$ruleSetArray=explode('|',$ruleSet);
foreach($ruleSetArray as $rule)
{
$this->splitRulesAndParameters($rule);
$methodName='validate'.ucfirst($rule);
$value = isset($data[$item]) ? $data[$item] : NULL;
if(method_exists($this, $methodName))
{
$this->$methodName($item,$value,$parameter) OR $valid=false;
}
}
}
return $valid;
}
And here is the splitRulesAndParameters function
public function splitRulesAndParameters($rule)
{
$position = strpos($rule, ':');
if($position !==false)
{
$parameter = substr($rule,$position + 1);
$rule = substr($rule,0,$position);
}
else
{
$parameter='';
}
}
Seeing as the problem goes away if you "inline" the code in splitRulesAndParameters, I suspect the $parameters variable is used in that method. If so, simply have that method return the value of this variable, and assign it to a variable local to the validate method you've posted here:
$parameters = $this->splitRulesAndParameters($rule);
After adding this to the splitRulsAndParameters method:
return $parameters;
The method itself also modifies the $rule value. Again: this $rule variable is local to each method. It may have the same name, but the value is a copy. Any changes you make to $rule in splitRulesAndParameters is not reflected by $rule in your validate method. If I were you, I'd write:
public function splitRulesAndParameters($rule)
{
$position = strpos($rule, ':');
if($position !==false)
{
return array(
'parameter' => substr($rule, $position+1),
'rule' => substr($rule, 0, $position)
);
}
return array(
'parameter' => null,//no param == null, IMO, change to '' if you want
'rule' => $rule
);
}
Then, to change the variables in validate:
$split = $this->splitRulesAndParameters($rule);
$rule = $split['rule'];
$parameter = $split['parameter'];
That ought to do it.
Side-note:
You seem to be validating everything that needs validating, even if the first validation failed. If I were you, I'd change this fugly statement:
$this->$methodName($item,$value,$parameter) OR $valid=false;
To a more efficient:
if (!$this->{$methodName}($item, $value, $parameter))
return false;//if validation fails, return false
That stops any further valiation from being executed: if one value is invalid, then just stop there. To continue is pointless, because the data-set is not entirely valid anyway.
Bonus:
Using a colon to separate the method name, and some parameter(s) does allow you to specify multiple params, too, and it allows you to simplify the splitRulesAndParameters some more:
protected function splitRulesAndParameters($rule)
{
$all = explode(':', $rule);
return array(
'rule' => array_shift($all),//removes first element in array
'params' => $all//rest of the array
);
}
Tweak this a little to better suite your needs
You can't just use a variable from inside a function in another function. You have to return the variable $parameter. Add a return statement to the end of splitRulesAndParameters and store the result in a variable inside validate ($parameter = $this->spli...).
You actually have two problems here, because you change the &rule variable inside your function, but you are passing it by reference. So after the fucntion is done the $rule variable is the same as it was before.
The way to solve this in the manner you are doing it right now would be to change the function to:
public function splitRulesAndParameters(&$rule)
{
$position = strpos($rule, ':');
if($position !==false)
{
$parameter = substr($rule,$position + 1);
$rule = substr($rule,0,$position);
}
else
{
$parameter='';
}
return $parameter;
}
and change the line
$this->splitRulesAndParameters($rule);
to
$parameter = $this->splitRulesAndParameters($rule);
Is it possible to (in some format), return a variable containing information from a function in PHP
eg.
function setuplogin($email,$pwd){
if(!$email || !$pwd){ return $error = 'not possible'; }
}
So that on the page where it was called
<?php echo $error;?>
would work
EDIT:
It would not be possible to simply echo the function as this same function could also be set to
return $success = 'congrats'; and called on page with <?php echo $success;?>
A function can only return a value (of any type). What you do with that value - e.g. assigning it to a variable or to different variables depending on the value returned - is solely the job of the caller and the function cannot influence this.
Of course your function could create a global variable by assigning to $GLOBALS['whatever'] but that's extremely ugly and if you call your function from another function it wouldn't even work the way you wanted. Another drawback would be that you'd always have to assign something to all of the variables - otherwise you'll end up with possibly undefined variables depending on what the function did and would need isset() checks in the code using those variables.
So what you are trying to do is not possible in a clean way. The closest would be retruning an array:
function foo() {
return array('success' => ..., 'error' => ...);
}
Then the caller could do e.g. $result = foo(); and then use $result['success'] and $result['error']
It sounds like what you want is to be able to return multiple things: whether the function succeeded or failed, and a message to go along with it. You can do that by returning an array:
return array('success' => true, 'message' => 'well done');
The caller can do:
$result = setuplogin(...);
echo $result['message'];
You can just set up the function to spit out the variable you want without using a "variable".
function setuplogin($email,$pwd){
if(!$email || !$pwd){ return 'not possible'; }
}
<?php echo setuplogin(); ?>
Or you can use global variables and call the $error outside the function:
$error = "";
function setuplogin($email,$pwd){
global $error;
if(!$email || !$pwd){ $error = 'not possible'; }
}
<?php echo $error; ?>
Of course the second one assumes that you would call the function before the echo.
How can I quickly validate if a GET or POST variable in CodeIgniter is both set and numeric for use as error or status messages in views?
It is very tedious to do something like this each time each time I want to check variables:
if ($this->input->get('error', True)) {
if (is_numeric($this->input->get('error', True))) {
$data['error'] = $this->input->get('error', True);
}
}
get_numeric_input() for CodeIgniter
mixed get_numeric_input ( string $name [, bool $required = True [, string $source = "GET" [, bool *$xss_clean* = True ]]] )
Below is a function that I created because I was tired of checking if GET and POST variables existed and were numeric.
This was mainly used when handling errors or status messages, because I could use redirect("original_page.php?error=1"); to pass an error to the original page. On the original page, I could simply do if (isset($error)) { … } and display a message depending on the value. However, it was necessary to check these variables before sending them to the view in the interest of security. This process proved to be quite repetitive and tedious.
This function below is to be added to the bottom of wwwroot/application/system/core/Input.php
It is to be used as follows:
Example 1:
function index() {
if ($error = $this->input->get_numeric_input('error', True, "GET", True)) {
$data['error'] = $error;
}
}
In this example, if $_GET['error'] is both set and numeric, it will set $data['error'] to that value. If it is either not set and/or not numeric, it will terminate the script.
Example 2:
function index() {
if ($error = $this->input->get_numeric_input('error', False, "POST", True)) {
$data['error'] = $error;
}
}
In this example, if $_POST['error'] is both set and numeric, it will set $data['error'] to that value. If it is either not set and/or not numeric, it will continue and not set any values in the $data array.
The first argument is the variable name to be checked. The second variable is the boolean that makes the check required or not. If you have this set to TRUE, then if the variable is not set OR if it is not numeric, it will show an error and immediately terminate the script. If set to False, then it will will simply return False, and the script will move on. The third variable is either POST or GET, and will determine if the function looks for the variable in the $_GET or $_POST arrays. Finally, the fourth variable indicated whether or not the values will be XSS_CLEAN when returned.
NOTE: Both the second, third, and fourth arguments are optional, and default to True, “GET,” and True, respectively.
Here is the code:
function get_numeric_input($name, $required = True, $source = "GET", $xss_clean = True) {
if ($source === "GET") {
if ($this->get($name, $xss_clean)) {
if (is_numeric($this->get($name, $xss_clean))) {
return $this->get($name, $xss_clean);
} else {
if ($required) {
show_error("$source variable $name is not numeric!");
log_message('error', "$source variable $name is not numeric!");
return False;
} else {
return False;
}
}
} else {
if ($required) {
show_error("$source variable $name is not set!");
log_message('error', "$source variable $name is not set!");
return False;
} else {
return False;
}
}
} elseif ($source === "POST") {
if ($this->post($name, $xss_clean)) {
if (is_numeric($this->post($name, $xss_clean))) {
return $this->post($name, $xss_clean);
} else {
if ($required) {
show_error("$source variable $name is not numeric!");
log_message('error', "$source variable $name is not numeric!");
return False;
} else {
return False;
}
}
} else {
if ($required) {
show_error("$source variable $name is not set!");
log_message('error', "$source variable $name is not set!");
return False;
} else {
return False;
}
}
}
}
A possible alternative is to extend the form validation so that you would have a way to validate $_GET aswell. Using the form validation library does save time imo (an extended version - fit to your needs - is advisable).
CodeIgniter Validation: possible to validate GET query strings? talks about this.
Just use an intermediary variable, for a short and fast code:
$input_error = $this->input->get('error');
$data['error'] = ctype_digit($input_error) ? $input_error : FALSE;
If you really want a one-liner:
function validate_integer_input($input) {
return ctype_digit($input) ? $input : FALSE;
}
$data['error'] = validate_integer_input($this->input->get('error'));
$data['error'] will always be set, which is a good thing, because $data will always be set in your view, so you can simply do if ($data) instead of if (isset($data)).
When dealing with GET and POST input you have to know some aspects of typing. For the most important:
A GET/POST input, of course if it is set, is always of type string.
Only '' (empty) and '0' strings evaluate to FALSE, all other values evaluate to TRUE.
ctype_digit() expects a string, but this code may pass it FALSE (from CI->input). But it's fine, as FALSE casts to an empty string.
As a side note, XSS filtering is not needed for this case.
XSS filtering has quite a performance impact and should be activated only when needed. A rule of thumb is that the filtering is needed for data which is displayed or included wherever in the HTML source.
For this case, we already made sure the input can only contain digits, so we're safe.
I find in my PHP pages I end up with lines and lines of code that look like this:
$my_id = isset($_REQUEST['my_id']) ? $_REQUEST['my_id'] : '';
$another_var = isset($_REQUEST['another_var']) ? $_REQUEST['another_var'] : 42;
...
Is there a better, more concise, or more readable way to check this array and assign them to a local variable if they exist or apply a default if they don't?
EDIT: I don't want to use register_globals() - I'd still have the isset problem anyway.
How about wrapping it in a function?
<?php
function getPost($name, $default = null) {
return isset($_POST[$name]) ? $_POST[$name] : $default;
}
a better method might be to create a singleton/static class to abstract away the details of checking the request data.
Something like:
class Request {
private $defaults = array();
private static $_instance = false;
function getInstance () {
if (!self::$_instance) {
$c = __CLASS__;
self::$_instance = new $c;
}
return self::$_instance;
}
function setDefaults($defaults) {
$this->defaults = $defaults;
}
public function __get($field) {
if (isset($_REQUEST[$field]) && !empty($_REQUEST[$field])) {
return $_REQUEST['field'];
} elseif (isset($this->defaults[$field])) {
return $this->defaults[$field];
} else {
return ''; # define a default value here.
}
}
}
you can then do:
# get an instance of the request
$request = Request::getInstance();
# pass in defaults.
$request->setDefaults(array('name'=>'Please Specify'));
# access properties
echo $request->name;
echo $request->email;
I think this makes your individual scripts loads cleaner and abstracts away the validation etc. Plus loads of scope with this design to extend it/add alternate behaviours, add more complicated default handling etc etc.
First, use $_POST for POSTed variables. $_REQUEST is a mashup of many different incoming variables, not just $_POST and could cause problems.
One solution for your question would be to create a function that handles the isset() logic.
function ForceIncomingValue($Key, $Default) {
if (!isset($_POST[$Key]))
return $Default;
else return $_POST[$Key];
}
first of all, NEVER use the $_REQUEST variable, it'll lead to bugs and other problems during development
function getPOST($key) {
if(isset($_POST[$key])) {
return $_POST[$key];
}
}
note that this code leaves the variable empty when $_POST[$key] was not set
you could also adapt that code to enable you to instead provide you with a (sensible) default when the value could not be loaded.
function getPOST($key, $default = NULL) {
if(isset($_POST[$key])) {
return $_POST[$key];
} else {
return $default;
}
}
Is the set of variables you're expecting known at the time of the script's writing, or do you want to do this for an arbitrary set of values? If the former is true, you could do something like this:
# This array would hold the names of all the variables you're expecting
# and a default value for that variable name
$variableNames = array (...);
foreach ($variableNames as $key => $default) {
if (isset ($_REQUEST[$key])) $$key = $_REQUEST[$key];
else $$key = $default;
}
Basically, this takes advantage of PHP's ability to evaluate variables to create other variables (hence the double-dollar for $$key--this means create a new variable whose name is the value of $key).
I haven't yet come up with a good solution to the latter situation.
PHP's null coalescing operator!
$username = $_GET['user'] ?? 'nobody';
For a lot of variables, with a requirement check, anyone is free to use my expect function.