Explode DB record into tabular format - php

I have a database connected to my site that is recording actions taken by a user on an application we have built. The application holds a number of images, which the user can view and download, and the application tracks, per user, which image they have viewed delimited by a comma
What I want to do is write a PHP script that will allow me to turn this delimited text string into a calculated table format
If the database has example records of:
1 | 1-A, 1-B, 2-A, 2-C
2 | 1-A
3 | 1-B, 2-C
4 |
5 | 1-A, 1-B, 1-C, 2-A
To which I wanted to write a script that would be able to output this as:
1-A = 3
1-B = 3
1-C = 1
2-A = 2
2-C = 2
(I want to point out, I'm not suggesting that I want to have variables named after each entry, with its calculated total as the value, I'm open to however is best to return this value)
My first step was to explode each record into an array, but then I wasn't sure as to my next step to turn this into something I can write into a table.
I realise the database is very poorly structured, but unfortunately I haven't written it, and so I have no ability to re-structure the data is stored.
Kind regards

this should work:
<?php
$values = array (
'1' => '1-A, 1-B, 2-A, 2-C',
'2' => '1-A',
'3' => '1-B, 2-C',
'4' => '',
'5' => '1-A, 1-B, 1-C, 2-A'
);
$valueCounts = array();
foreach($values as $value)
{
foreach(explode(', ', $value) as $val)
{
if(!key_exists($val, $valueCounts))
{
if($val) $valueCounts[$val] = 1;
}
else
{
$valueCounts[$val]++;
}
}
}
ksort($valueCounts);
foreach($valueCounts as $value => $count)
{
echo "$value = $count<br />";
}
?>
result:
1-A = 3
1-B = 3
1-C = 1
2-A = 2
2-C = 2
if you're not sure how to populate the $values array, please paste the database code and I will try and incorporate it into the above.

Related

Parse strings of numbers and domain/subdomain strings, group, then sum numbers in each group

In PHP, I have an array that shows how many times user clicked on each individual domain like this:
$counts = [
"900,google.com",
"60,mail.yahoo.com",
"10,mobile.sports.yahoo.com",
"40,sports.yahoo.com",
"300,yahoo.com",
"10,stackoverflow.com",
"20,overflow.com",
"5,com.com",
"2,en.wikipedia.org",
"1,m.wikipedia.org",
"1,mobile.sports",
"1,google.co.uk"
];
How can i use this input as a parameter to a function and returns a data structure containing the number of clicks that were recorded on each domain AND each subdomain under it. For example, a click on "mail.yahoo.com" counts toward the totals for "mail.yahoo.com", "yahoo.com", and "com". (Subdomains are added to the left of their parent domain. So "mail" and "mail.yahoo" are not valid domains. Note that "mobile.sports" appears as a separate domain near the bottom of the input.)
Sample output (in any order/format):
calculateClicksByDomain($counts) =>
com: 1345
google.com: 900
stackoverflow.com: 10
overflow.com: 20
yahoo.com: 410
mail.yahoo.com: 60
mobile.sports.yahoo.com: 10
sports.yahoo.com: 50
com.com: 5
org: 3
wikipedia.org: 3
en.wikipedia.org: 2
m.wikipedia.org: 1
mobile.sports: 1
sports: 1
uk: 1
co.uk: 1
google.co.uk: 1
The first step I am stuck at is how can to get subdomains from for example
"mobile.sports.yahoo.com"
such that result is
[com, yahoo.com, sports.yahoo.com, mobile.sports.yahoo.com]
This code would work:
$counts = [
"900,google.com",
"60,mail.yahoo.com",
"10,mobile.sports.yahoo.com",
"40,sports.yahoo.com",
"300,yahoo.com",
"10,stackoverflow.com",
"20,overflow.com",
"5,com.com",
"2,en.wikipedia.org",
"1,m.wikipedia.org",
"1,mobile.sports",
"1,google.co.uk"
];
function calculateClicksByDomain($dataLines)
{
$output = [];
foreach ($dataLines as $dataLine) {
[$count, $domain] = explode(',', $dataLine);
$nameParts = [];
foreach (array_reverse(explode('.', $domain)) as $namePart) {
array_unshift($nameParts, $namePart);
$domain = implode('.', $nameParts);
$output[$domain] = ($output[$domain] ?? 0) + $count;
}
}
return $output;
}
print_r(calculateClicksByDomain($counts));
See: https://3v4l.org/o5VgJ#v8.0.26
This function walks over each line of the data and explodes it into a count and a domain. After that it explodes the domain by the dots, reverses it, and walks over those name parts. In that loop it reconstructs the various subdomains and counts them into the output.

php multi dimensional array's

I am pulling data out of a table that has these fields:
zipcode,city,state,county
My question is that some zip codes are in multiple cities, and some cities are in multiple zip codes... so is there a way to have all the data put into an array, then group all of the zip codes in order, then build a table out of that, so that it puts them in order, but if the data is redundant, like the zip, city, state and county are already in the array, then it skips it?
so then I can print it to the browser using echo, into a table like this:
74801 | Shawnee, Oklahoma | Pottawatomie
74801 | Bethel, Oklahoma | Pottawatomie
74801 | Johnson, Oklahoma | Pottawatomie
74851 | McLoud, Oklahoma | Pottawatomie
74851 | Dale, Oklahoma | Pottawatomie
etc.
But in the case of these:
74015 | CATOOSA, Oklahoma | Rogers
74015 | COTOOSA, Oklahoma | Rogers
Because those are duplicates in those fields (not in the rest of the table), I need it to skip showing it twice.
I think it is something like this:
$zipArray = array();
$zipCode = $dbhhandle->zip;
$cityName = $dbhhandle->city;
$countyName = $dbhhandle->county;
if($zipArray[$zipCode][$cityName] != $countyName) {
$zipArray[$zipCode][$cityName] = $countyName;
}
but I'm not sure if that is the right way to do it.
Then once I have the array built, how do I build the table?
Your code looks pretty close, but it's missing the state. So change the elements of the array into associative arrays with state and county elements.
Also, you need to check whether there's an entry for the zip code at all, before checking whether it's a duplicate, otherwise you'll access an undefined index.
$zipArray = array();
$zipCode = $dbhhandle->zip;
$cityName = $dbhhandle->city;
$countyName = $dbhhandle->county;
$stateName = $dbhandle->state;
if(!isset($zipArray[$zipCode][$cityName]) || $zipArray[$zipCode][$cityName]['county'] != $countyName) {
$zipArray[$zipCode][$cityName] = array('county' => $countyName, 'state' => $stateName);
}
To display the table, you use nested loops.
foreach ($zipArray as $zip => $cities) {
foreach ($cities as $city => $cityData) {
echo "<tr><td>$zip</td><td>$city, {$cityData['state']}</td><td>{$cityData['county']}</td></tr>";
}
}

PHP Multi Dimensional Array : Phone Prefix vs Courier Name

I'm thinking to use Array to store this tiny data instead using Database. But, I have difficulties to 'call' the data since this is Multi Dimensional Array.
Here's my situation :
I have several phone prefix from different cities :
$CityA = array("021","031","041","051");
$CityB = array("011","012","013","014");
$CityC = array("111","112","113","114");
Also, I have several courier for those cities :
$CityA = array("FedEx", "TNT", "DHL");
$CityB = array("YYY Cargo", "USPS");
$CityC = array("UPS", "Regular Mail", "XXX Cargo");
what I need is :
INPUT : Phone Prefix, for example 021
OUTPUT : FedEx, TNT or DHL >> Randomly selected
here's another examples :
012 >> YYY Cargo (Randomly selected from "YYY Cargo", "USPS")
112 >> UPS
etc.
It's pretty easy with MySQL, but I want to reduce database connection by using Array. how to do this?
You should use associative arrays for easier access. Since you want to access info by phone prefix, you should use these as keys for the first array. Then, your second array can be indexed by city, as below:
$cities = array( 021 => "CityA", 031 => "CityA", 011 => "CityB")
$couriers = array( "CityA" => array("FedEx", "TNT", "DHL"),
"CityB" => array("YYY Cargo", "USPS"),
"CityC" => array("UPS", "Regular Mail", "XXX Cargo"));
So, in your example, for retrieving a courier for prefix 021 you can acces it like this:
$city = $cities[$phone_prefix];
$courier_key = array_rand($couriers[$city]);
$courier_name = $couriers[$city][$courier_key];
So you want to specify an area code from "area-code array A", and then generate a random courier from "courier array A"?
Quick and dirty, but you could generate a random number between 0 and count($couriersA) - 1 (the number of entries in that array) and then select that entry in the array.
If not, you could look at combinations - so getting all the possible pairs of area code and courier, then choosing one randomly from that.
Try this code. You will get random courier for City code ( $value='111'; )
$CityA = array("021","031","041","051");
$CityB = array("011","012","013","014");
$CityC = array("111","112","113","114");
$courierA = array("FedEx", "TNT", "DHL");
$courierB = array("YYY Cargo", "USPS");
$courierC = array("UPS", "Regular Mail", "XXX Cargo");
$value = '111'; // Your City Code
if(in_array($value, $CityA)){
shuffle($courierA);
echo $courierA[0];
}
else if(in_array($value, $CityB)){
shuffle($courierB);
echo $courierB[0];
}
else if(in_array($value, $CityC)){
shuffle($courierC);
echo $courierC[0];
}
Output: YYY Cargo or USPS

How can I put rows of MySQL data under the appropriate titles using PHP?

I have the following MySQL table structure:
num field company phone website
1 Gas abcd 123456789 abcd.com
2 Water efgh 987654321 efgh.com
3 Water ijkl 321654987 ijkl.com
4 Heat mnop 987654321 mnop.com
5 Gas qrst 123789654 qrst.com
...
Is it possible with PHP (maybe using some mixture of GROUP_BY and ORDER_BY) to echo the data to the screen in the following format:
Gas:
abcd qrst
123456789 123789654
abcd.com qrst.com
Water:
efgh ijkl
987654321 321654987
efgh.com ijkl.com
Heat:
mnop
321654987
mnop.com
The exact format of it isn't important. I just need for the different rows of data to be listed under the appropriate field with none of the fields repeated. I've been trying to figure this out for a while now, but I'm new to PHP and I can't seem to figure out how to do this, if it's even possible, or if there's a better way to organize my data to make it easier.
To avoid performing a "Gas" query, a "Water" query and a "Heat" query, you could order the results by "field" and then handle the display in PHP...
SELECT
Field,
Company,
Phone,
Website
FROM
tblYourTable
ORDER BY
Field
In your PHP loop, you would need to keep tabs on your current "Field" and start a new list when it changes. For example:
$CurrentField = '';
... loop
if ($MyData->Field != $CurrentField) {
$CurrentField = $MyData->Field;
....
}
... end loop
I will assume that you know how to retrieve MySQL data into an array... so, we have:
[0] {
num => 1,
field => "Gas",
company => "abcd",
phone => "123456789",
website => "abcd.com"
}
[1] ... (so on)
Then create a loop like:
foreach($data as $row) {
$service = $row["field"]; //Water, Gas, etc...
unset($row["field"]); //do not add this
foreach($row as $key => $value) {
$field[$service][$key][] = $value;
}
}
The resulting array will be something like:
$field["Gas"]["company"][0] = "abcd";
$field["Gas"]["company"][1] = "qrst";
$field["Water"]["company"][0] = "efgh";
...
$field["Gas"]["phone"][0] = "123456789";
$field["Gas"]["phone"][1] = "123789654";
$field["Water"]["phone"][0] = "987654321";
...
In that way you can then generate the output:
foreach($field as $service => $infoarr) {
echo $service."\n";
foreach($infoarr as $info => $datarr) {
foreach($datarr as $datum) {
echo $datum."\t";
}
echo "\n";
}
echo "\n";
}
Theorically (untested) will output:
Gas
abcd qrst
123456789 123789654
Water
efgh ...
I hope you find it useful... There should be a better way, but I didn't thought
too much about it...

LinkedIn type friends connection required in php

I am creating a custom social network for one of my clients.
In this I am storing the friends of a user in the form of CSV as shown below in the user table
uid user_name friends
1 John 2
2 Jack 3,1
3 Gary 2,4
4 Joey 3
In the above scenario if the logged in user is John and if he visits the profile page of Joey, the connection between them should appear as
John->Jack->Gary->Joey
I am able to establish the connection at level 1 i.e
If Jack visits Joey's profile I am able to establish the following :
Jack->Gary->Joey
But for the 2nd level I need to get into the same routine of for loops which I know is not the right solution + I am not able to implement that as well.
So, can someone please help me with this?
Thanks in Advance,
Akash
P:S I am not in a position to change the db architecture :(
Here's some bfs code I had written in ruby; it should give you a good enough idea of how things work to translate it to php. the other change you'll need to make is to replace graph[current] with a db query to get the current user's friends.
def bfs(graph, start, stop)
queue = [start]
visited = {}
parents = {}
current = nil
while true
if queue.empty?
return nil
end
current = queue.shift
if current == stop
return read_path(current, parents)
end
visited[current] = true
graph[current].each do |i|
if not visited[i] and not queue.index(i)
parents[i] = current
queue.push(i)
end
end
end
end
def read_path(node, parents)
a = [node]
while parents[node]
a.push(parents[node])
node = parents[node]
end
return a.reverse
end
GRAPH = {
"a" => ["b", "c"],
"b" => ["c", "d"],
"c" => ["a", "e"],
"d" => ["b", "c", "f"],
"e" => ["c", "f"]
}
path = bfs(GRAPH, "a", "f")
p path
Here's some sample code:
<?php
$currentUID = 1; // The logged in user
$pageUID = 4; // The user whose page is being visited
// Parse the CSV
$csv = explode("\n", $csvData);
$csvlen = count($csv);
for($i=0;$i<$csvlen;$i++) {
$csv[$i] = explode(",", $csv[$i]);
}
function getFriends($csv, $uid) {
foreach($csv as $user)
if($user[0] == $uid)
return explode(',', $user[2]);
}
$userFriends = getFriends($csv, $currentUID);
$pageFriends = getFriends($csv, $pageUID);
$friendPool = array();
foreach($userFriends as $friend) {
$hisFriends = getFriends($friend);
foreach($hisFriends as $subFriend) {
if(in_array($subFriend, $pageFriends)) {
if(isset($friendPool[$friend]))
$friendPool[$friend][] = $subFriend;
else
$friendPool[$friend] = array( $subFriend );
}
}
}
foreach($friendPool as $friend=>$subFriends)
foreach($subFriends as $subFriend)
echo "$currentUID -> $friend -> $subFriend -> $pageUID\n";

Categories