Check if postcode is in multiple arrays? - php

I have 3 different areas, MyArea1, MyArea2, MyArea3. Each of these have an array of postcodes:
$myArea1=array("AB1","AC2","AD1");
$myArea2=array("BC1","BC2","BC3");
$myArea3=array("CD1","CD2","CD3");
The postcodes I need to check would be like the following "BC2 4YZ".
The following won't work as it checks for a complete match:
if (in_array($row['postcode'], $myArea1)) { $Area = 'Area 1'; }
else if (in_array($row['postcode'], $myArea2)) { $Area = 'Area 2'; }
else if (in_array($row['postcode'], $myArea3)) { $Area = 'Area 3'; }
else { $Area = 'No Match'; }
I've got the following that works:
foreach ($myArea1 as $myArea1pc) {
if (strpos($row['postcode'],$myArea1pc) !== false) {
$Area = 'Area 1';
}
}
However is there a way of looping this for all of my arrays?
Edit: There may sometimes be postcodes such as "BC24" in my arrays.

I would try to use in_array for this.
$input = $row['postcode'];
$areas = array(
'Area 1' => array("AB1","AC2","AD1"),
'Area 2' => array("BC1","BC2","BC3"),
'Area 3' => array("CD1","CD2","CD3"),
);
// Take out the first 3 letter:
$part = substr(trim(str_replace(' ', '', $input)), 0, -3);
$Area = 'No match';
// Find which "area" array contains it
foreach ($areas as $k => $v) {
if (in_array($part, $v)) {
$Area = $k;
break;
}
}

Related

Data Matrix Barcode split to different data

I have a data matrix barcode that have the input
Data Matrix Barcode = 0109556135082301172207211060221967 21Sk4YGvF811210721
I wish to have output as below:-
Items
Output
Gtin
09556135082301
Expire Date
21-07-22
Batch No
60221967
Serial No
Sk4YGvF8
Prod Date
21-07-21
But My coding didn't detect after the space
$str = "0109556135082301172207211060221967 21Sk4YGvF811";
if ($str != null){
$ais = explode("_",$str);
for ($aa=0;$aa<sizeof($ais);$aa++)
{
$ary = $ais[$aa];
while(strlen($ary) > 0) {
if (substr($ary,0,2)=="01"){
$gtin = substr($ary,2,14);
$ary = substr($ary,-(strlen($ary)-16));
}
else if (substr($ary,0,2)=="17"){
$expirydate = substr($ary,6,2)."-".substr($ary,4,2)."-20".substr($ary,2,2);
$ary = substr($ary,-(strlen($ary)-8));
}
else if (substr($ary,0,2)=="10"){
$batchno = substr($ary,2,strlen($ary)-2);
$ary = "";
}
else if (substr($ary,0,2)=="21"){
$serialno = substr($ary,2,strlen($ary)-2);
$ary = "";
}
else if (substr($ary,0,2)=="11"){
$proddate = substr($ary,6,2)."-".substr($ary,4,2)."-20".substr($ary,2,2);
$ary = substr($ary,-(strlen($ary)-8));
}
else {
$oth = "";
}
}
}
My code output https://onecompiler.com/php/3yg6gs5ea didn't come out the result I expected. Anyway to modify it?
Solution
You can use a regex to make it short and easy.
Note
Your string does not contain all the characters of the code given in the description.
Code
$str = "0109556135082301172207211060221967 21Sk4YGvF811210721";
$datePattern = '/(\d\d)(\d\d)(\d\d)/';
$dateReplacement = '\3-\2-\1';
$matches = [];
preg_match('/(?<gtin>.{18})(?<expire>.{6})(?<batch>.*?)\s(?<serial>.{12}(?<prod>.{6}))/', $str, $matches);
$matches['expire'] = preg_replace($datePattern, $dateReplacement, $matches['expire']);
$matches['prod'] = preg_replace($datePattern, $dateReplacement, $matches['prod']);
$matches = array_filter($matches, fn($value, $key) => !is_numeric($key), ARRAY_FILTER_USE_BOTH);
$keyMap = [
'gtin' => 'Gtin',
'expire' => 'Expire Date',
'batch' => 'Batch No.',
'serial' => 'Serial No.',
'prod' => 'Production Date',
];
foreach ($keyMap as $key => $output) {
echo "<tr><td>$output</td><td>{$matches[$key]}</td></tr>\n";
}
Output
<tr><td>Gtin</td><td>010955613508230117</td></tr>
<tr><td>Expire Date</td><td>21-07-22</td></tr>
<tr><td>Batch No.</td><td>1060221967</td></tr>
<tr><td>Serial No.</td><td>21Sk4YGvF811210721</td></tr>
<tr><td>Production Date</td><td>21-07-21</td></tr>

Grouping array based on the key value similarity

Let's say I have an array like that:
$data[0]['name'] = 'product 1 brandX';
$data[0]['id_product'] = '77777777';
$data[1]['name'] = 'brandX product 1';
$data[1]['id_product'] = '77777777';
$data[2]['name'] = 'brandX product 1 RED';
$data[2]['id_product'] = '77777777';
$data[3]['name'] = 'product 1 brandX';
$data[3]['id_product'] = '';
$data[4]['name'] = 'product 2 brandY';
$data[4]['id_product'] = '8888888';
$data[5]['name'] = 'product 2 brandY RED';
$data[5]['id_product'] = '';
I am trying to group them by their similarities (name or id_product).
That would be the expected final array:
$uniques[0]['name'] = 'product 1 brandX'; //The smallest name for the product
$uniques[0]['count'] = 4; //Entry which has all the words of the smallest name or the same id_product
$uniques[0]['name'] = 'product 2 brandY';
$uniques[0]['count'] = 2;
That's what I tried so far:
foreach ($data as $t) {
if (!isset($uniques[$t['id_product']]['name']) || mb_strlen($uniques[$t['id_product']]['name']) > mb_strlen($t['name'])) {
$uniques[$t['id_product']]['name'] = $t['name'];
$uniques[$t['id_product']]['count']++;
}
}
But I can't be based on the id_product because sometimes it will be the same product but one will have the id and the other one no. I have to check the name also, but couldn't manage to get it done.
I'm basing my answer on two assumptions about how products should be grouped:
Although id_product can be missing, where it is present, it is
correct and sufficient to match two products; and
For two product names to match, the longest name (name with the most
words) must contain all of the words in the shortest name (name with
the fewest words).
Given these assumptions, here is a function to determine if two individual products match (products should be grouped together) and a helper function to get words from names:
function productsMatch(array $product1, array $product2)
{
if (
!empty($product1['id_product'])
&& !empty($product2['id_product'])
&& $product1['id_product'] === $product2['id_product']
) {
// match based on id_product
return true;
}
$words1 = getWordsFromProduct($product1);
$words2 = getWordsFromProduct($product2);
$min_word_count = min(count($words1), count($words2));
$match_word_count = count(array_intersect_key($words1, $words2));
if ($min_word_count >= 1 && $match_word_count === $min_word_count) {
// match based on name similarity
return true;
}
// no match
return false;
}
function getWordsFromProduct(array $product)
{
$name = mb_strtolower($product['name']);
preg_match_all('/\S+/', $name, $matches);
$words = array_flip($matches[0]);
return $words;
}
This function can be used to group the products:
function groupProducts(array $data)
{
$groups = array();
foreach ($data as $product1) {
foreach ($groups as $key => $products) {
foreach ($products as $product2) {
if (productsMatch($product1, $product2)) {
$groups[$key][] = $product1;
continue 3; // foreach ($data as $product1)
}
}
}
$groups[] = array($product1);
}
return $groups;
}
And then this function can be used to extract the shortest name and count for each group:
function uniqueProducts(array $groups)
{
$uniques = array();
foreach ($groups as $products) {
$shortest_name = '';
$shortest_length = PHP_INT_MAX;
$count = 0;
foreach ($products as $product) {
$length = mb_strlen($product['name']);
if ($length < $shortest_length) {
$shortest_name = $product['name'];
$shortest_length = $length;
}
$count++;
}
$uniques[] = array(
'name' => $shortest_name,
'count' => $count,
);
}
return $uniques;
}
So combining all 4 functions, you can get the uniques as follows (tested with php 5.6):
$data[0]['name'] = 'product 1 brandX';
$data[0]['id_product'] = '77777777';
$data[1]['name'] = 'brandX product 1';
$data[1]['id_product'] = '77777777';
$data[2]['name'] = 'brandX product 1 RED';
$data[2]['id_product'] = '77777777';
$data[3]['name'] = 'product 1 brandX';
$data[3]['id_product'] = '';
$data[4]['name'] = 'product 2 brandY';
$data[4]['id_product'] = '8888888';
$data[5]['name'] = 'product 2 brandY RED';
$data[5]['id_product'] = '';
$groups = groupProducts($data);
$uniques = uniqueProducts($groups);
var_dump($uniques);
Which gives output:
array(2) {
[0]=>
array(2) {
["name"]=>
string(16) "product 1 brandX"
["count"]=>
int(4)
}
[1]=>
array(2) {
["name"]=>
string(16) "product 2 brandY"
["count"]=>
int(2)
}
}
I don't think this will solve your problem, but it may get you moving forward again
$data = [];
$data[0]['name'] = 'product 1 brandX';
$data[0]['id_product'] = '77777777';
$data[1]['name'] = 'brandX product 1';
$data[1]['id_product'] = '77777777';
$data[2]['name'] = 'brandX product 1 RED';
$data[2]['id_product'] = '77777777';
$data[3]['name'] = 'product 1 brandX';
$data[3]['id_product'] = '';
$data[4]['name'] = 'product 2 brandY';
$data[4]['id_product'] = '8888888';
$data[5]['name'] = 'product 2 brandY RED';
$data[5]['id_product'] = '';
$data = collect($data);
$tallies = [
'brand_x' => 0,
'brand_y' => 0,
'other' => 0
];
$unique = $data->unique(function ($item) use (&$tallies){
switch(true){
case(strpos($item['name'], 'brandX') !== false):
$tallies['brand_x']++;
return 'product X';
break;
case(strpos($item['name'], 'brandY') !== false):
$tallies['brand_y']++;
return 'product Y';
break;
default:
$tallies['other']++;
return 'other';
break;
}
});
print_r($unique);
print_r($tallies);
I think the best way to solve this is to use a unique product_id, but if you want create unique keys by finding similarities in the name field you can use preg_split to transform names to arrays and then use array_diff to find an array of difference. 2 names are considered unique if their difference count is lower than 2. I create this function it returns similar names in $arr or false if not found:
function get_similare_key($arr, $name) {
$names = preg_split("/\s+/", $name);
// get similaire key from $arr
foreach( $arr as $key => $value ) {
$key_names = preg_split("/\s+/", $key);
$diff = array_diff($key_names, $names);
if ( count($diff) <= 1 ) {
return $key;
}
}
return false;
}
Here is a working demo here

Check for empty values in associative array

I'm having a hard time checking for empty values in my associative array. And if a value is empty/null replace it with the wording "not entered"
My $_SESSION['gift'] array:
Array
(
[0] => Array
(
[giftGiveMy] => 1a
[giftTo] => 2a
)
[1] => Array
(
[giftGiveMy] => 1b
[giftTo] => '' //### empty ###
)
)
if (empty($_SESSION['gift']) && 0 !== $_SESSION['gift']) {
$gifts = "No specific gifts identified.\n";
} else {
$gifts = [];
foreach( $_SESSION['gift'] as $value) {
$gifts[] = "I give my ". $value['giftGiveMy'] ." to ". $value['giftTo'] .".\n";
}
$gifts = join($gifts);
}
The above outputs:
I give my 1a to 2a.
I give my 1b to .
I would like it read:
I give my 1a to 2a.
I give my 1b to not entered.
You can replace all empty and NULL value with not entered with the help of array_walk_recursive and use you code as it is
array_walk_recursive($arrayMain, 'not_entered');
function not_entered(& $item, $key) {
if (($item === "") || ($item ==NULL)){
$item = "not entered";
}
}
var_dump($arrayMain);
Just use foreach to loop all values and check if it's empty
$emptyText = '<b>not entered</b>';
// `empty` will also be true if element does not exist
if (empty($_SESSION['gift'])) {
$gifts = "No specific gifts identified.\n";
} else {
$gifts = [];
foreach($_SESSION['gift'] as $value) {
$myGive = !empty($value['giftGiveMy']) ? $value['giftGiveMy'] : $emptyText;
$giftTo = !empty($value['giftTo']) ? $value['giftTo'] : $emptyText;
$gifts[] = "I give my {$myGive} to {$giftTo}.";
}
$gifts = implode("\r\n", $gifts); // Or `<br/>` if outputted to HTML
}
You should modify your code and write it this way:
if (!isset($_SESSION['gift']) || empty($_SESSION['gift'])) {
$gifts = "No specific gifts identified.\n";
} else {
foreach( $_SESSION['gift'] as $value) {
$gift_to = !empty($value['giftTo']) ? $value['giftTo'] : '<strong>Not entered<strong>';
$gifts[] = "I give my ". $value['giftGiveMy'] ." to ". $gift_to .".\n";
}
}
You might want to try this:
if (empty($_SESSION['gift']) && 0 !== $_SESSION['gift']) {
$gifts = "No specific gifts identified.\n";
} else {
$gifts = [];
foreach( $_SESSION['gift'] as $value) {
$gifts[] = "I give my ". $value['giftGiveMy'] ." to ". (!empty($value['giftTo']) ? $value['giftTo'] : '<b>not entered</b>') .".\n";
}
$gifts = join($gifts);
}
If you would like to make it a little cleaner you could extract the ternary operator into something like this;
$giftTo = !empty($value['giftTo']) ? $value['giftTo'] : '<b>not entered</b>';
$gifts[] = "I give my ". $value['giftGiveMy'] ." to ". $giftTo .".\n";
Try:
$arr = $_SESSION['gift'];
foreach($arr as $key => $array) {
if($array['giftGiveMy'] == null || empty($array['giftGiveMy'])) {
$arr[$key]['giftGiveMy'] = 'not entered.';
}
if($array['giftTo'] == null || empty($array['giftTo'])) {
$arr[$key]['giftTo'] = 'not entered.';
}
}
I'd write that this way:
$gifts = "No specific gifts identified.\n";
$filter = function($str) {
return empty($str) ? 'not entered' : $str;
};
if(!empty($_SESSION['gift'])) {
$gifts = '';
array_walk($_SESSION['gift'], function($given) use(&$gifts,$filter){
$gifts .= 'I give my ' . $filter($given['giftGiveMy']) . ' to ' . $filter($given['giftTo']) . ".\n";
});
}
You can use for the below code also there is no need any extra Php functions.
$arr = array(
0 => array(
'giftGiveMy' => '1a',
'giftTo' => '2a'
),
1 => array(
'giftGiveMy' => '1b',
'giftTo' => ''
)
);
$str = '';
if (!empty($arr)) {
foreach ($arr as $key => $value) {
if ($value['giftGiveMy'] == '')
$value['giftGiveMy'] = 'not entered';
if ($value['giftTo'] == '')
$value['giftTo'] = '<strong>not entered</strong>';
//$new[$key] = $value;
$str .= "I give my " . $value['giftGiveMy'] . " to " . $value['giftTo'] . "<br />";
}
}else {
$str = 'No specific gifts identified.<br />';
}
echo $str;
This validates an associative array with empty() (see array_filter), but may not respond to the original question.
<?php
$var = array();
$var['position'] = 'executive';
$var['email'] = 'a#email.com';
$var['message'] = 'This is the message';
$var['name'] = 'John Doe';
$var['telephone'] = '123456789';
$var['notneededparam'] = 'Nothing';
$expectedParams = ['position', 'email', 'message', 'name', 'telephone'];
$params = array_intersect_key($var, array_flip($expectedParams));
// check existence of keys and that they are valid
if(count($params) != count($expectedParams) || count(array_filter($params)) != count($expectedParams)){
echo "not valid\n";
die();
}
extract($params);
var_dump($name);
Other functions used here: array_flip(), array_intersect_key(), count(), extract(), var_dump(),

bulk PHP isset generator

I just joined a project developed in plain php ( As in no frameworks). I have a table that has 213 fields and according to the guidelines i have to do an isset, prepare string, prepare number for 212 fields.
This is a lot of repetitive code and most of the tables in this system are huge. As such i would like to save time by developing an isset generator but before I go re-inventing the wheel i would like to ask: Can anyone point me in the direction of such a generator that returns the isset code? Something similar to http://www.fpmgonline.com/mysql_insert.php
Edited to add code
Supposing $data is my $_POST array , instead of checking many fields one by one I wanted to generate a bulk isset code
Here's is some sample code
<?php
$data = Array('name' => 'Sample name', 'desc' => 'Sample description');
if (isset($data['name'])) {
$name = trim($data['name']);
} else {
$return[] = ' Name code is required';
}
if (isset($data['desc'])) {
$desc = trim($data['desc']);
} else {
$return[] = ' Description is name is required';
}
if (isset($data['age'])) {
$age = trim($data['age']);
} else {
$age = 0;
}
?>
Thank you.
There is no need for "generating" code. That's why you have data structures, loops and conditionals in programming languages.
$data = Array('name' => 'Sample name', 'desc' => 'Sample description', 'age' => 'Foo bar');
$defaults = Array('age' => 0);
$messages = Array('name' => ' Name code is required', 'desc' => ' Description is name is required');
for($data as $key => $val) {
if (isset($data[$key])) {
$$key = trim($data[$key]);
} else if (isset($defaults[$key])) {
$$key = $defaults[$key];
} else {
$return[] = $messages[$key];
}
}
The need to use variable variables ($$key) here also is plain wrong. When working with "dynamic" data you should not need to work with a separate variable for each item. I'd refactor that into this:
$clean_data = Array();
for($data as $key => $val) {
if (isset($data[$key])) {
$clean_data[$key] = trim($data[$key]);
} else if (isset($defaults[$key])) {
$clean_data[$key] = $defaults[$key];
} else {
$return[] = $messages[$key];
}
}
Also $data should not be whatever comes from $_POST. It should be everything that's in your fields list and then check if it's present in $_POST, so that you don't end up running arbitrary code based on user input.
I did a simple one for the isset:
$data = Array('name' => 'Sample name', 'desc' => 'Sample description');
bulkisset($data, 'name,description,age');
function bulkisset($data, $table_fields) {
$code = '';
$inputs = explode(',', $table_fields);
foreach ($inputs as $key) {
$code .= '<br/>if (isset($data["' . $key . '"])){'
. '$name = trim($data["' . $key . '"]);} else {$' . $key . ' ="";};';
}
echo $code;
}
This might not be the best way to check data but with my hands tied I think this will save me some time.

Array highest value or create next value?

I have an array of names and id's.
Array(
0=>array(
name=>New York,
id=>45763448349,
can=0
),
1=>array(
name=>New York2,
id=>45763464566,
can=0
),
3=>array(
name=>New York3,
id=>45763464854,
can=0
),
4=>array(
name=>New York4,
id=>45763464955,
can=0
),
5=>array(
name=>New York5,
id=>45763464745,
can=0
),
6=>array(
name=>New York6,
id=>45763464235,
can=1
)
)
For example (there will be different names (not all New York)) and I have an x variable with a name (for example x=New York) what I need to do is find the highest name and get the id and then make sure can is 1 otherwise specific the next highest name.
For example let's assume that I have x=New York so I look through the array and find that the highest array name is New York6. I see that can=1 so I just get the id. Now if can != 1 then I could specific New York7.
NOTE: This array will contain many different values (not all New York, I just used those for an example)
Now how on earth would I even get started?
In code:
function city_cmp($record_a, $record_b) {
return strcmp($record_a["name"], $record_b["name"];
}
usort($cities, 'city_cmp');
end($cities);
$city = current($cities);
do {
if ($city["can"] === 1) {
$can_city = $city;
break;
}
} while ($city = prev($cities));
Note: optionally, you could skip the break and make $can_city part of your while condition. Some prefer that as it can make the loop exit condition clearer.
In quick steps:
usort() the array
use end() to point at the end of the array and prev() until you find a can=1.
Since it's a multi-dimensional array (I'll call it $array) you probably have to loop through it once to find relevant data.
$highest_id = array('id' => 0, 'count' => 0, 'can' => 0);
for each ( $array AS $key => $data )
{
if ( substr($data['name'],0,strlen($x)) == $x )
{
$current_count = (int) substr($data['name'],strlen($x));
if ( $current_count > $highest_id['count'] )
{
$highest_id = array('id' => $data['id'], 'count' => $current_count, 'can' => $data['can']);
}
}
}
if ( $highest_id['can'] == 1 )
{
$id = $highest_id['id'];
}
else
{
// can is not 1 => specify new $x
}
Start by dividing your task into smaller ones. The first filter criterion seems to be can=1. Let's check that with array_filter.
$ar = array(array('name'=>'New York', 'id'=>45763448349, 'can'=>1), array('name'=>'New York2', 'id'=>45763464566, 'can'=>0), array('name'=>'New York3', 'id'=>45763464854, 'can'=>0), array('name'=>'New York4', 'id'=>45763464955, 'can'=>0), array('name'=>'New York5', 'id'=>45763464745, 'can'=>0), array('name'=>'New York6', 'id'=>45763464235, 'can'=>1), array('name'=>'New Yorkistan', 'id'=>0, 'can'=1));
$ar = array_filter($ar, function($el) {return $el['can'];});
// Now $ar contains the entries 'New York', 'New York2', and 'New Yorkistan'
Now, filter out the entries which do not match New York(and a number).
$ar = array_filter($ar, function($el) {
$search = 'New York';
$name = $ar['name'];
$potentialNumber = substr($name, strlen($search));
return ((substr($name, 0, strlen($search)) == $search) && // starts with NY
($potentialNumber == '' || is_numeric($potentialNumber)); // [0-9]*
});
// $ar contains only 'New York' and 'New York6' now
Now, you just need some sorting with usort and pick the first element:
usort($ar, function($el1, $el2) {
$id1 = $el1['id']; $id2 = $el2['id'];
if ($id1 == $id2) return 0;
return $id1 < $id2 ? 1 : -1;
});
if (count($ar) > 0) {
$result = $ar[0];
} else {
// Nothing matched your criteria
}
Something like this:
//$my_array is your array of values
//$string = 'New York'; your search term
$id = false;
for($i = count($my_array) - 1; $i >= 0; $i++) {
if($id === false) {
if(strpos($my_array[$i]['name'], $string) !== false && $my_array[$i]['can'] == 1) {
$id = $my_array[$i]['id'];
}
}
}
//Insert it if no id was found
if($id === false) {
$id = 'something';
$can = 1;
array_push($my_array, array('name' => $string, 'id' => $id, 'can' => $can));
}
Does that work?
edit
(In case it's not obvious, $string is whatever you are searching for)

Categories