How to search $_POST for dynamic added input values? - php

I have a form where i add inputs on the fly.
The names of the inputs start the same but has a number added on the end:
<input type="number" name="number_of_floors_house_'+i+'">
Now, when i post my form i would like to loop threw this inputs.
So i need something like array_search($_POST['number_of_floors_house_%']
Or find all $POST['keys'] that starts with 'number_of_floors_house' and loop them threw to get it's values :)
Can you help please?
EDIT
I've tried:
$houses_and_floors = array_search('number_of_floors_house_%', $_POST);
var_dump($houses_and_floors);

Change your input to something like this:
<input type="number" name="number_of_floors['+i+']">
The square brackets make the input submit as an array, so you could then loop through all the values easier:
foreach($_POST['number_of_floors'] as $house_number => $value) {
// $house_number will be whatever number was added to the form element.
// $value is the actual input boxes value
}

You could use an array_filter() to pick out the pieces of $_POST you actually want like this
//fake up a post array
$_POST = ['aa'=>1, 'bb'=>2, 'number_of_floors_house_1'=>2, 'number_of_floors_house_2'=>2,'number_of_floors_house_3'=>4];
function picker($v, $k)
{
return strpos($k, 'number_of_floors_house') !== FALSE;
}
$res = array_filter($_POST, 'picker', ARRAY_FILTER_USE_BOTH);
print_r($res);
RESULT
Array
(
[number_of_floors_house_1] => 2
[number_of_floors_house_2] => 2
[number_of_floors_house_3] => 4
)

You can filter for array keys matching a given prefix with array_filter() and strncmp():
$prefix = 'number_of_floors_';
$length = strlen($prefix);
$nof = array_filter($_POST, function($key) use ($prefix, $length) {
return strncmp($prefix, $key, $length) === 0;
}, ARRAY_FILTER_USE_KEY);
This will filter your post data for all array members with the defined prefix. Note that we're checking the prefix length outside the function to avoid a redundant repeated evaluation inside the function (which is executed for once each array member). You could, of course, also just hard-code this for a single use-case and skip the leading variables above:
$nof = array_filter($_POST, function($key) {
return strncmp('number_of_floors_', $key, 17) === 0;
}, ARRAY_FILTER_USE_KEY);
...which would compare the first 17 characters of each key with the defined string. Again, you could also do this with substr() in place of strncmp(), with return substr($key, 0, $length) === $prefix as the filter condition. I chose the former for this example, since it's a function explicitly for the "binary safe string comparison of the first n characters".

Related

Replace repeating value with zero in PHP string

The following is the code
<?php
$id ="202883-202882-202884-0";
$str = implode('-',array_unique(explode('-', $id)));
echo $str;
?>
The result is
202883-202882-202884-0
for $id ="202883-202882-202882-0";, result is 202883-202882-0
I would like to replace the duplicate value with zero, so that the result should be like 202883-202882-0-0, not just remove it.
and for $id ="202883-0-0-0";, result should be 202883-0-0-0. zero should not be replaced, repeating zeros are allowed.
How can I archive that?
More info:
I want to replace every duplicate numbers. Because this is for a product comparison website. There will be only maximum 4 numbers. each will be either a 6 digit number or single digit zero. all zero means no product was selected. one 6 digit number and 3 zero means, one product selected and 3 blank.
Each 6 digit number will collect data from database, I dont want to allow users to enter same number multiple times (will happen only if the number is add with the URL manually.).
Update: I understand that my question was not clear, may be my English is poor.
Here is more explanation, this function is for a smartphone comparison website.
The URL format is sitename.com/compare.html?id=202883-202882-202889-202888.
All three numbers are different smartphones(their database product ID).
I dont want to let users to type in the same product ID like id=202883-202882-202882-202888. It will not display two 202882 results in the website, but it will cause some small issues. The URL will be same without change, but the internal PHP code should consider it as id=202883-202882-202888-0.
The duplicates should be replaced as zero and added to the end.
There will be only 4 numbers separated by "-".
The following examples might clear the cloud!
if pid=202883-202882-202889-202888 the result should be 202883-202882-202889-202888
if pid=202883-202883-202883-202888 the result should be 202888-0-0-0
if pid=202883-202882-202883-202888 the result should be 202883-202882-202888-0
if pid=202882-202882-202882-202882 the result should be 202882-0-0-0
I want to allow only either 6 digit numbers or single digit zero through the string.
if pid=rgfsdg-fgsdfr4354-202883-0 the result should be 202883-0-0-0
if pid=fasdfasd-asdfads-adsfds-dasfad the result should be 0-0-0-0
if pid=4354-45882-445202882-202882 the result should be 202882-0-0-0
It is too complicated for me create, I know there are bright minds out there who can do it much more efficiently than I can.
You can do a array_unique (preserves key), then fill the gaps with 0. Sort by key and you are done :)
+ on arrays will unify the arrays but prioritizes the one on the left.
Code
$input = "0-1-1-3-1-1-3-5-0";
$array = explode('-', $input);
$result = array_unique($array) + array_fill(0, count($array), 0);
ksort($result);
var_dump(implode('-',$result));
Code (v2 - suggested by mickmackusa) - shorter and easier to understand
Fill an array of the size of the input array. And replace by leftover values from array_unique. No ksort needed. 0s will be replaced at the preserved keys of array_unique.
$input = "0-1-1-3-1-1-3-5-0";
$array = explode('-', $input);
$result = array_replace(array_fill(0, count($array), 0), array_unique($array));
var_export($result);
Working example.
Output
string(17) "0-1-0-3-0-0-0-5-0"
Working example.
references
ksort - sort by key
array_fill - generate an array filled with 0 of a certain length
This is another way to do it.
$id = "202883-202882-202882-0-234567-2-2-45435";
From the String you explode the string into an array based on the delimiter which in this case is '-'/
$id_array = explode('-', $id);
Then we can loop through the array and for every unique entry we find, we can store it in another array. Thus we are building an array as we search through the array.
$id_array_temp = [];
// Loop through the array
foreach ($id_array as $value) {
if ( in_array($value, $id_array_temp)) {
// If the entry exists, replace it with a 0
$id_array_temp[] = 0;
} else {
// If the entry does not exist, save the value so we can inspect it on the next loop.
$id_array_temp[] = $value;
}
}
At the end of this operation we will have an array of unique values with any duplicates replaced with a 0.
To recreate the string, we can use implode...
$str = implode('-', $id_array_temp);
echo $str;
Refactoring this, using a ternary to replace the If,else...
$id_array = explode('-', $id);
$id_array_temp = [];
foreach ($id_array as $value) {
$id_array_temp[] = in_array($value, $id_array_temp) ? 0 : $value;
}
$str = implode('-', $id_array_temp);
echo $str;
Output is
202883-202882-0-0-234567-2-0-45435
This appears to be a classic XY Problem.
The essential actions only need to be:
Separate the substrings in the hyphen delimited string.
Validate that the characters in each substring are in the correct format AND are unique to the set.
Only take meaningful action on qualifying value.
You see, there is no benefit to replacing/sanitizing anything when you only really need to validate the input data. Adding zeros to your input just creates more work later.
In short, you should use a direct approach similar to this flow:
if (!empty($_GET['id'])) {
$ids = array_unique(explode('-', $_GET['id']));
foreach ($ids as $id) {
if (ctype_digit($id) && strlen($id) === 6) {
// or: if (preg_match('~^\d{6}$~', $id)) {
takeYourNecessaryAction($id);
}
}
}

array_filter with element modification [duplicate]

This question already has answers here:
Explode string on commas and trim potential spaces from each value
(11 answers)
Closed 6 months ago.
I'm trying to make a clean array from a string that my users will define.
The string can contain non-valid IDs, spaces, etc. I'm checking the elements using a value object in a callback function for array_filter.
$definedIds = "123,1234,1243, 12434 , asdf"; //from users panel
$validIds = array_map(
'trim',
array_filter(
explode(",", $definedIds),
function ($i) {
try {
new Id(trim($i));
return true;
} catch (\Exception $e) {
return false;
}
}
)
);
This works fine, but I'm applying trim twice. Is there a better way to do this or a different PHP function in which I can modify the element before keeping it in the returned array?
NOTE: I also could call array_map in the first parameter of array_filter, but I would be looping through the array twice anyway.
It depends on whether you care about performance. If you do, don't use map+filter, but use a plain for loop and manipulate your array in place:
$arr = explode(',', $input);
for($i=count($arr)-1; $i>=0; $i--) {
// make this return trimmed string, or false,
// and have it trim the input instead of doing
// that upfront before passing it into the function.
$v = $arr[$i] = Id.makeValid($arr[$i]);
// weed out invalid ids
if ($v === false) {
array_splice($arr, $i, 1);
}
}
// at this point, $arr only contains valid, cleaned ids
Of course, if this is inconsequential code, then trimming twice is really not going to make a performance difference, but you can still clean things up:
$arr = explode(',', $input);
$arr = array_filter(
array_map('Id.isValidId', $arr),
function ($i) {
return $i !== false;
}
);
In this example we first map using that function, so we get an array of ids and false values, and then we filter that so that everything that's false gets thrown away, rather than first filtering, and then mapping.
(In both cases the code that's responsible for checking validity is in the Id class, and it either returns a cleaned id, or false)
Actually you can do it by different way but If I were you then I'll do it this way. Here I just used only one trim
<?php
$definedIds = "123,1234,1243, 12434 , asdf"; //from users panel
function my_filter($b){
if(is_numeric($b)){
return true;
}
}
print '<pre>';
$trimmed = array_map('trim',explode(',',$definedIds));
print_r(array_filter($trimmed,my_filter));
print '</pre>';
?>
Program Output:
Array
(
[0] => 123
[1] => 1234
[2] => 1243
[3] => 12434
)
DEMO: https://eval.in/997812

PHP remove empty, null Array key/values while keeping key/values otherwise not empty/null

I have an array thats got about 12 potential key/value pairs. That are based off a _POST/_GET
The keys are not numeric as in 0-n, and I need to retain the keys with there values where applicable. My issue is I know that on occasion a key will be passed where the value is null, empty, or equal to ''. In the event thats the case I want to trim out those keys before processing my array. As running down the line without something there is going to break my script.
Now a while back I either made or found this function (I don't remember which its been in my arsenal for a while, either way though).
function remove_array_empty_values($array, $remove_null_number = true)
{
$new_array = array();
$null_exceptions = array();
foreach($array as $key => $value)
{
$value = trim($value);
if($remove_null_number)
{
$null_exceptions[] = '0';
}
if(!in_array($value, $null_exceptions) && $value != "")
{
$new_array[] = $value;
}
}
return $new_array;
}
What I would love to do is very similar to this, however this works well with arrays that can have n-n key values and I am not dependent upon the key as well as the value to determine whats what where and when. As the above will just remove everything basically then just rebuilt the array. Where I am stuck is trying to figure out how to mimic the above function but where I retain the keys I need.
If I understand correctly what you're after, you can use array_filter() or you can do something like this:
foreach($myarray as $key=>$value)
{
if(is_null($value) || $value == '')
unset($myarray[$key]);
}
If you want a quick way to remove NULL, FALSE and Empty Strings (""), but leave values of 0 (zero), you can use the standard php function strlen as the callback function:
// removes all NULL, FALSE and Empty Strings but leaves 0 (zero) values
$result = array_filter( $array, 'strlen' );
Source: http://php.net/manual/en/function.array-filter.php#111091
array_filter is a built-in function that does exactly what you need. At the most you will need to provide your own callback that decides which values stay and which get removed. The keys will be preserved automatically, as the function description states.
For example:
// This callback retains values equal to integer 0 or the string "0".
// If you also wanted to remove those, you would not even need a callback
// because that is the default behavior.
function filter_callback($val) {
$val = trim($val);
return $val != '';
}
$filtered = array_filter($original, 'filter_callback');
if you want to remove null, undifined, '', 0, '0', but don't remove string ' '
$result = array_filter( $array, 'ucfirst' );
Filtering the array for PHP 7.4 and above use this
// Filtering the array
$result = array_filter($array, fn($var) => ($var !== NULL && $var !== FALSE && $var !== ""));
use +1 with your key variable to skip null key in array
foreach($myarray as $key=>$value)
{
echo $key+1; //skip null key
}

How to count non-empty entries in a PHP array?

Consider:
[name] => Array ( [1] => name#1
[2] => name#2
[3] => name#3
[4] => name#4
[5] =>
[6] =>
[7] =>
[8] =>
[9] =>
)
$name = $_POST['name']
I want the result to be 4.
count ($name) = 9
count (isset($name)) = 1
count (!empty($name)) = 1
I would think that last one would accomplish what I need, but it is not (the empty entries are from unfilled inputs on the form).
You can use array_filter to only keep the values that are “truthy” in the array, like this:
array_filter($array);
If you explicitly want only non-empty, or if your filter function is more complex:
array_filter($array, function($x) { return !empty($x); });
# function(){} only works in in php >5.3, otherwise use create_function
So, to count only non-empty items, the same way as if you called empty(item) on each of them:
count(array_filter($array, function($x) { return !empty($x); }));
However, as empty() is only a shorthand for 'variable is set and the value is truthy', you don't really gain anything from that, because if your array contains values such as FALSE or "0", those would count as empty as well, same as with the plain call to array_filter.
The better way is to be explicit about what you want to count, e.g. if you want to exclude empty strings only, then use:
array_filter($array, function($x) { return ($x !== ""); });
count(array_filter($name));
Possible Solution: First you need to remove empty/null, false and zero values from an array and then count remaining values of an array
If you no need to remove zero values from an array, but remove null and false values
count(array_filter($arrayName, 'strlen'));
//"strlen" use as second parameter if you no need to remove zero '0' values
if you need to remove zero, null and false values from an array
count(array_filter($arrayName));
Here's a simple calculation function:
function non_empty(array $a) {
return array_sum(array_map(function($b) {return empty($b) ? 0 : 1;}, $a));
}
This will preserve array indexes if your form handling function needs them, like when you're associating the third input on name to the third value of another input set, and there are empty inputs in between them.
The easyest aproach is to use count() and array_filter() functions (eventually with an additional callback within array_filter() when we need type compatibility checking, but when the result of default empty() function is enough for us we don't need it).
However, we can also achieve that by using the array_reduce() function, and this approach is slightly more optimal in terms of computational complexity:
$initial = 0;
$count = array_reduce($arr, function($carry, $item) {
$carry += empty($item) ? 0 : 1;
return $carry;
}, $initial);
The $count variable counts all non-empty items in the array $arr.
Note that, the condition can be changed if someone wishes, e.g. instead of empty($item) we can use a stronger condition $item === '', etc.
When the array $arr is empty, $initial is returned.

selecting an array key based on partial string

I have an array and in that array I have an array key that looks like, show_me_160 this array key may change a little, so sometimes the page may load and the array key maybe show_me_120, I want to now is possible to just string match the array key up until the last _ so that I can check what the value is after the last underscore?
one solution i can think of:
foreach($myarray as $key=>$value){
if("show_me_" == substr($key,0,8)){
$number = substr($key,strrpos($key,'_'));
// do whatever you need to with $number...
}
}
I ran into a similar problem recently. This is what I came up with:
$value = $my_array[current(preg_grep('/^show_me_/', array_keys($my_array)))];
you would have to iterate over your array to check each key separately, since you don't have the possibility to query the array directly (I'm assuming the array also holds totally unrelated keys, but you can skip the if part if that's not the case):
foreach($array as $k => $v)
{
if (strpos($k, 'show_me_') !== false)
{
$number = substr($k, strrpos($k, '_'));
}
}
However, this sounds like a very strange way of storing data, and if I were you, I'd check if there's not an other way (more efficient) of passing data around in your application ;)
to search for certain string in array keys you can use array_filter(); see docs
// the array you'll search in
$array = ["search_1"=>"value1","search_2"=>"value2","not_search"=>"value3"];
// filter the array and assign the returned array to variable
$foo = array_filter(
// the array you wanna search in
$array,
// callback function to search for certain sting
function ($key){
return(strpos($key,'search_') !== false);
},
// flag to let the array_filter(); know that you deal with array keys
ARRAY_FILTER_USE_KEY
);
// print out the returned array
print_r($foo);
if you search in the array values you can use the flag 0 or leave the flag empty
$foo = array_filter(
// the array you wanna search in
$array,
// callback function to search for certain sting
function ($value){
return(strpos($value,'value') !== false);
},
// flag to let the array_filter(); know that you deal with array value
0
);
or
$foo = array_filter(
// the array you wanna search in
$array,
// callback function to search for certain sting
function ($value){
return(strpos($value,'value') !== false);
}
);
if you search in the array values and array keys you can use the flag ARRAY_FILTER_USE_BOTH
$foo = array_filter(
// the array you wanna search in
$array,
// callback function to search for certain sting
function ($value, $key){
return(strpos($key,'search_') !== false or strpos($value,'value') !== false);
},
ARRAY_FILTER_USE_BOTH
);
in case you'll search for both you have to pass 2 arguments to the callback function
You can also use a preg_match based solution:
foreach($array as $str) {
if(preg_match('/^show_me_(\d+)$/',$str,$m)) {
echo "Array element ",$str," matched and number = ",$m[1],"\n";
}
}
filter_array($array,function ($var){return(strpos($var,'searched_word')!==FALSE);},);
return array 'searched_key' => 'value assigned to the key'
foreach($myarray as $key=>$value)
if(count(explode('show_me_',$event_key)) > 1){
//if array key contains show_me_
}
More information (example):
if array key contain 'show_me_'
$example = explode('show_me_','show_me_120');
print_r($example)
Array ( [0] => [1] => 120 )
print_r(count($example))
2
print_r($example[1])
120

Categories