Can this PHP code be improved? - php

Is there a better way to do this simple task below? Like with an array or even another method?
<?PHP
// current way
if ($city != NULL) {
$city = FilterALLHTML($city);
}
if ($state != NULL) {
$state = FilterALLHTML($state);
}
if ($title != NULL) {
$title = FilterALLHTML($title);
}
if ($division != NULL) {
$division = FilterALLHTML($division);
}
?>
Here is my current function
function FilterALLHTML($document) {
//old array line //"'<[\/\!]*?[^<>]*//?//>'si",// strip html
$text = strip_tags($document);
$search = array ("/f.?u.?c.?k/i",
"/(s|$).?h.?i.?t/i",
'/(potspace|mycrib|palbolt)/i');
$text = preg_replace ($search, '', $text);
return $text;
}
UPDATE - Ok my new function after the suggestions from this post thanks guys
function FilterALLHTML($var) {
//old array line //"'<[\/\!]*?[^<>]*//?//>'si",// strip html
if ($var != null){
$text = strip_tags($var);
$search = array ("/f.?u.?c.?k/i",
"/(s|$).?h.?i.?t/i",
'/(potspace|mycrib|palbolt|pot space)/i');
$text = preg_replace ($search, '', $text);
return $text;
}
return null;
}

Change your FilterALLHTML function to do the null check and have it return null?
Then you can throw away all the ifs.
Example:
function FilterALLHTML($input)
{
if ($input === null)
return null;
// Original code, I'll just use strip_tags() for a functional example
return strip_tags($input);
}
Edit:
I felt like sharing an alternative to variable variables, as I don't really like the idea of using string literals instead of variable names. References all the way :)
function FilterALLHTML(&$text)
{
if ($text !== null)
{
// Omitted regex bit for simplicity
$text = strip_tags($text);
}
}
$city = "<b>New York</b>";
$state = null;
$title = "<i>Mr.</i>";
$fields = array(&$city, &$state, &$title);
foreach ($fields as &$var)
FilterALLHTML($var);
(note: FilterALLHTML implementation differs from first example)

Yes, use PHP's variable variables.
$vars = array('city','state','title','division');
foreach($vars as $v) {
if ($$v != null) $$v = FilterAllHTML($$v);
}
If you know for a fact that all the variables have been previously defined, then you don't need the null check. Otherwise, the null check will prevent E_NOTICE errors from triggering.

foreach (array('city', 'state', 'title', 'division') as $var) {
if ($$var != null) {
$$var = FilterALLHTML($$var);
}
}
Like Thorarin I'd suggest having your FilterALLHTML function check for null instead though.

zombat's answer is the best, but I'd add that you shouldn't really be checking for null either. If for some reason FilterAllHTML has a problem with null values, which it shouldn't, put the check for null in the FilterAllHTML function definition.
$vars = array('city', 'state', 'title', 'division');
foreach($vars as $var) {
$$var = FilterAllHTML($$var);
}

Well, you could already consider writing a function because you do exactly the same thing four times.
Assuming FilterALLHTML is not a custom function.
function Filter($var)
{
if ($var != null)
{
return FilterALLHTML($var);
}
return null;
}
Or just include the null check in the FilterALLHTML function and return null from there, if needed.
So, if you can change FilterALLHTML then you'd do it like this:
function FilterALLHTML($var)
{
if ($var == null)
{
return null;
}
else
{
//do your filtering
return $filteredVar;
}
}

Adding to Thorarin's answer, you can change your filterall function in order to accept an array as input, and passing it by reference it will modify the arrays' content.
$tofilter = array($city,$state,$division,$title);
filterall($tofilter);

I didn't see it mentioned, you could always pass the parameters by reference to skip the repeated assignments:
function FilterALLHTML(&$var)
{
if ($var == null)
{
$var = null;
}
else
{
$var = strip_tags($var);
}
}
I believe you can also store references in the array but i haven't tried it.
foreach (array(&$city, &$state, &$title, &$division) as $var)
{
FilterALLHTML($var);
}

I don't think you can improve the performance, but you can shorten the syntax, but it will end up being the same to the interpreter
<?PHP
$city = ($city == NULL) ? "default value" : FilterALLHTML($city);
$state = ($state == NULL) ? "default value" : FilterALLHTML($state);
$title = ($title == NULL) ? "default value" : FilterALLHTML($title);
$division = ($division == NULL) ? "default value" : FilterALLHTML($division);
?>
"default value" should be replaced with what you would like the value to be if the variable is null

Related

explode() expects parameter 2 to be string, array given

I have designed below code where i am using explode to explode below data,
"10.74.10.1", "10.75.10.132"
however i getting below error
"explode() expects parameter 2 to be string, array given in line.."
Can someone please suggest whats wrong in my code.
This is my full code:
public function pagesviewlogsAction()
{
// Checks authorization
$this->acl->doCheck($this);
-- language: lang-html --> // Validates request
$requestObj = new PagesviewlogEventRequest();
$requestObj->userid = (Utils::validatePattern(Utils::REGEXP_SECLOGS_USERID, (($json->userid) ?? FALSE) )) ? $json->userid:NULL;
$requestObj->clientip = array();
//if (isset($json->clientip) && $json->clientip != '' && $json->clientip != NULL) {
if (isset($json->clientip) && is_string($json->clientip)){
$tmp = explode(',', $json->clientip);
foreach ($tmp as $key => $ipValue) {
$requestObj->clientip[] = (Utils::validatePattern(Utils::REGEXP_SECLOGS_IP, ((trim($ipValue)) ?? FALSE) )) ? trim($ipValue):NULL;
}
}
}
foreach (get_object_vars($requestObj) as $key => $value) {
switch ($key) {
case 'clientip':
// ...
break;
default:
// Other cases
if ($value === FALSE) {
return new JsonModel([
'status' => 'FAILED',
'errorField' => $key,
'message'=> 'Parameters "' . $key . '" is missing or invalid.',
'data' => NULL
]);
}
break;
}
}
}
}
You condition :
if (isset($json->clientip) && $json->clientip != '' && $json->clientip != NULL)
can return true with an array.
better use something like this :
if (isset($json->clientip) && is_string($json->clientip))
The function explode() will convert a string to an array using a given separator, in your case ","
Since $json->clientip is already an array, the simple(not the best) solution is to change the code to:
$requestObj->clientip = array();
if (is_array($json->clientip)) {
foreach ($json->clientip as $key => $ipValue) {
$requestObj->clientip[] = (Utils::validatePattern(Utils::REGEXP_SECLOGS_IP, ((trim($ipValue)) ?? FALSE) )) ? trim($ipValue):NULL;
}
} else {
//handle the other option here. like string or object
}
and it depends on the source of the $json->clientip to make sure you have the correct approach in case you don't receive an array.
Exactly as it's telling you,
"10.74.10.1", "10.75.10.132" is an array. Explode requires a string because it creates an array based on the seperator ,
Try a var_dump() on your $json->clientip and see what it looks like, you may have to re-work your code a bit here.
Can I propose a possibility? I would check for both possible cases. If array execute one way, if string execute your explode.
if (!isset($json->clientip)) {
// thow exception or return call
}
$requestObj->clientip = [];
if (is_array($json->clientip)) {
array_walk($json->clientip, function($ipValue) use(&$requestObj) {
$ipValue = trim($ipValue);
$requestObj->clientip[] = (Utils::validatePattern(Utils::REGEXP_SECLOGS_IP, (($ipValue) ?? FALSE) )) ? $ipValue:NULL;
});
} else if (is_string($json->clientip)) {
// execute your explode
}
Also I would advice to check on Marshallers to help you parse logic in your code to tidy it up more instead of leaving it all into the same place. So your Utils::validatePattern could be a Marshaller in my opinion

How to check a called string within a php string is set?

I'm looking to call multiple strings and concatenate them into a single string. I want to be able to check that all of the strings that are being called are set, WITHOUT having to isset(); every single string that is used.
What I'd ideally like to have:
<?php
$name = "John Smith";
$age = "106";
$favAnimal = "pig";
$email = "john#smith.com";
$sport = "tennis";
$userDescription = "My name is $name, I am $age years old, I like $sport.";
if(allStringsSet($userDescription)){
echo $userDescription; //Or do something else
}
?>
You will notice that I'm not calling all of the strings, as in my application not all of the strings will be used all of the time. Also my application will be choosing from about 50 strings and I need to be able to check any are set without a pile of isset();s everywhere.
I expect that the isset checking needs to happen before the $userDescription is declared. How can I check an unknown set of strings to see if they are set?
Use an object with custom getter and setter.
class CustomStrings()
{
protected $data;
public function __set($key, $value) {
$this->data[$key] = $value;
}
public function __get($key) {
if (isset($data[$key])) {
return $data[$key];
}
return false;
}
public function getDescription($description) {
// regex to find the words following : (or any other char)
// look for the variables, and do whatever handling you want if they're not found
// return whatever you want
// IF you don't want to do a regex, you can do the following
foreach ($this->data as $key => $value) {
$description = str_replace(":$key", $value, $description);
}
if (strpos(':', $description) !== FALSE) {
return $description;
}
return false; // or whatever error handling you want
}
}
$strings = new CustomStrings();
$strings->name = 'John';
$strings->age = 16;
$strings->sport = 'Football';
$description = $strings->getDescription("My name is :name, I am :age years old, I like :sport");
You will have all your variables stored in the CustomStrings object, with the proper keys, and instead of writing $name, you write :name.
You do the isset handling only once, in the getDescription function.
I didn't write the regex since I'm lazy. If you want to use : in your strings, replace it with something you won't be using.
Good luck!
If you need to have ALL variables defined, PHP's isset() supports multiple values, so you could do this
<?php
$name = "John Smith";
$age = "106";
$favAnimal = "pig";
$email = "john#smith.com";
$sport = "tennis";
if(isset($name, $age, $favAnimal, $email, $sport)) {
$userDescription = "My name is $name, I am $age years old, I like $sport.";
echo $userDescription; //Or do something else
}
?>
You should put them in array and use loop.
$data = array();
$data['name'] = "John Smith";
$data['age'] = "106";
$data['favAnimal'] = "pig";
$data['email'] = "john#smith.com";
$data['sport'] = "tennis";
$userDescription = "My name is $name, I am $age years old, I like $sport.";
$required_fields = array('name', 'age', 'favAnimal', 'email', 'sport');
if(checkData($data,$required_fields)) echo 'all fields are ok';
else echo 'not all fields are OK';
function checkData($data, $requiredFields)
{
foreach($requiredFields as $field)
{
if((array_key_exists($field, $data) && !empty($data[$field])) == false) return false;
}
return true;
}
Funcion check data takes 2 arguments both are arrays.
$data is the data to be checked.
$requiredFields is the array of required fields which needs to be set and musn't be empty
Why don't you store your strings in an array?
You could use a foreach loop then. This way you would have to use isset() just once!
$strings = new Array('string1', 'string2', 'string3')
foreach($strings as $str)
{
if(isset($str))
{
//do something..
}
}
One possible solution if you want have variables as you have and not use isset:
Define your string in this way:
$userDescription = "My name is [name], I am [age] years old, I like [sport].";
Or you dont have to update your string this way, you just change quotes from " to ' and variables will not be parsed.
Now, get all "variables" from your string (text inside [] from example above). For this use regular expression with (preg_split() or something else).
Now use those as variables of variables and test if they are not empty.
eg:
for ($i = 0; $i < counr($result); $i++)
{
if (($result[$i] == 'name') && (${$results[$i]} == "")) echo "Name is empty"
if (($result[$i] == 'age') && (is_int(${$results[$i]}) == false)) echo "Age is empty"
....
}
Above code is not working PHP, ist more or less pseudocode and steps how it can be done.
Another way is to use the E_NOTICE generated when undefined variables are in your string, that way, you automatically check ONLY for the variables in your string.
The problem is, you can't CATCH E_NOTICE, you have to use a custom error handler:
<?php
function handleError($errno, $errstr, $errfile, $errline, array $errcontext)
{
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
$var1 = "one";
$var2 = "two";
$var4 = "four";
error_reporting(E_ALL);
set_error_handler('handleError');
try {
echo "Hey $var1, I like $var2 but not $var3 . Tell that to $var4";
//This will throw a Notice: Undefined variable: var3 in /t.php on line 8
} catch (Exception $e) {
echo "Well, it looks like some vars were not set.";
}
restore_error_handler()
?>
It is a bit ugly, but 100% automatic.

Undefined indexes in PHP. Generic solution required

I have been searching Stack Overflow and the rest of the web, and I am starting to believe that there is no generic solution for undefined indexes.
I have a massive PHP application with several form and at the end of the script I call all the form's inputs and put them together to display a summary of all the inputs.
echo $_POST['FirstName'];
echo $_POST['MiddleName'];
echo $_POST['LastName'];
I know how to check each occurence like
if ( !isset($_POST['MiddleName']) ) { $_POST['MiddleName'] = '' }
Is there a way to automatically capture all undefined indexes and then set them to 0 or null?
It's as simple as looping trough an array of all indexes that may be defined:
$indexes_that_MUST_be_defined_but_can_be_empty = array(
'FirstName',
* * *
'LastName'
);
foreach($indexes_that_MUST_be_defined_but_can_be_empty as $index) {
if( ! isset($_POST[$index])) {
$_POST[$index] = NULL;
}
}
Or even you can preset different defaults like this:
$indexes_that_MUST_be_defined_but_can_be_empty = array(
'FirstName' => NULL,
* * *
'LastName' => NULL
);
$_POST = array_merge($indexes_that_MUST_be_defined_but_can_be_empty, $_POST);
If you really just want to suppress the warnings, you can use # like in:
echo htmlspecialchars(#$_POST['any_index']);
but I really don't recommend this.
EDIT:
Here's one more possible solution. A "magical" function that uses a pointer:
function null_if_not_defined(&$variable) {
return isset($variable) ? $variable : NULL;
}
// Usage:
echo htmlspecialchars(null_if_not_defined($_POST['any_index']));
You can do it using below function.
function setNullValue($arr)
{
$newarr = array();
foreach($arr as $key => $ar)
{
if($ar == "")
{
$newarr[$key] = 0;
}
else
{
$newarr[$key] = $ar;
}
}
return $newarr;
}
print_r(setNullValue($_POST));
If you want to show only those indexes with assigned values, you could do something like this:
foreach ($_POST as $index => $value) {
echo "{$index}: {$value}<br/>";
}
you can also create a simple function for this purpose:
$p = function($item) {
return isset($_POST[$item]) ? $_POST[$item] : null;
};
Now you can use it as such :
echo $p('MiddleName');
foreach($_POST as $key=>$value) {
if($value == "") $_POST[$key] = 0;
}

Function to Make Empty String NULL for MySQL Insertion in PHP

This is similar question to MySQL and PHP - insert NULL rather than empty string but I'm still encountering the problem.
I'm trying to create a function so that an empty string is inserted as a NULL into MySQL.
I create the function IsEmptyString:
function IsEmptyString($val){
if (trim($val) === ''){$val = "NULL";}
}
Before inserting the the variable, I escape it and then I call the function above. I've also tried $val = NULL;
What am I doing wrong? Also should I call the function before escaping?
You need to return $val at the end of the function:
function IsEmptyString($val){
if (trim($val) === ''){$val = "NULL";}
return $val;
}
You're not returning the value. This should work
function IsEmptyString($val){
if (trim($val) === ''){$val = "NULL";}
return $val;
}
Also you're assigning your variable to a string and not null.
This line $val = "NULL";
should be
$val = null;
Also see PHP's isset() and empty() functions.
alternativly, you can pass val as reference.
function IsEmptyString(&$val){
if (trim($val) === ''){$val = "NULL";}
}
however, be carefull not to send "'".$val."'" to the database;
Either you can return the result with return...
function IsEmptyString($val)
{
if (trim($val) === '')
return 'NULL';
else
return $val;
}
...or you have to pass the variable as reference (note the & before the $val)
function IsEmptyString(&$val)
{
if (trim($val) === '')
$val = 'NULL';
}
Looks like a good candidate for a ternary operator:
function valOrNull($val) {
return (trim($val) === '') ? NULL : $val;
}

collecting multiple GET or POST values

I have a form that passes something like in a URL
?choice=selection+A&choice=selection+C
I'm collecting it in a form with something like (I remember that $_GET is any array)
$temp = $_GET["choice"];
print_r($temp);
I'm only getting the last instance "selection C". What am I missing
I am assuming 'choice' is some kind of multi-select or checkbox group? If so, change its name in your html to 'choice[]'. $_GET['choice'] will then be an array of the selections the user made.
If you don't intend to edit the HTML, this will allow you to do what you're looking to do; it will populate the $_REQUEST superglobal and overwrite its contents.
This assumes PHP Version 5.3, because it uses the Ternary Shortcut Operator. This can be removed.
$rawget = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : false;
$rawpost = file_get_contents('php://input') ?: false;
$target = $rawget;
$_REQUEST = array();
if ($target !== false) {
$pairs = explode('&',$rawget);
foreach($pairs as $pair) {
$p = strpos($pair,'=');
if ($p === false && !empty($pair)) {
$_REQUEST[$pair] = null;
}
elseif ($p === 0 || empty($pair)) {
continue;
}
else {
list($name, $value) = explode('=',$pair,2);
$name = preg_replace('/\[.*\]/','',urldecode($name));
$value = urldecode($value);
if (array_key_exists($name, $_REQUEST)) {
if (is_array($_REQUEST[$name])) {
$_REQUEST[$name][] = $value;
}
else {
$_REQUEST[$name] = array($_REQUEST[$name], $value);
}
}
else {
$_REQUEST[$name] = $value;
}
}
}
}
As it stands, this will only process the QueryString/GET variables; to process post as well, change the 3rd line to something like
$target = ($rawget ?: '') . '&' . ($rawpost ?: '');
All that having been said, I'd still recommend changing the HTML, but if that's not an option for whatever reason, then this should do it.

Categories