Merging data from two different data sets (Facebook & MySQL) - php

I'm wondering if this is the best way to tackle this issue. I am merging a Facebook users friends data, (from facebook - returns a multi array) with the votes from the users in that list that voted (from MySQL).
This is how I accomplished this. I'm a junior developer and looking for help on making my code as optimized as possible.
public function getFriendVotes(){
global $facebook;
// Get The users friends that use this app from facebook
$friends = $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user)"
);
// Create an array of just the ids
foreach($friends as $friend){
$userids[] = $friend['uid'];
}
// Create a string of these ids
$idstring = implode(",", $userids);
// Get the votes from only the users in that list that voted
$result = $this->db->query(
"SELECT vote, userid FROM user_votes WHERE userid IN ($idstring)"
);
// Create a new result set (multi array). Include the data from the first
// Facebook query, but include only those who voted and append their votes
// to the data
$row = $result->fetch_assoc();
foreach($friends as $friend){
if($row['userid'] == $friend['uid']){
$return[$count] = $friend;
$return[$count]['vote'] = $row['vote'];
$row = $result->fetch_assoc();
$count++;
}
}
return $return;
}

I asume that fql_query does support mysql syntax and it would be more efficient to use LEFT JOIN instead creatig extra query, here is my version of your code:
public function getFriendVotes(){
global $facebook;
// Get The users friends that use this app from facebook
$friends = $facebook->api_client->fql_query("
SELECT DISTINCT u.uid,u.first_name,u.last_name
FROM user AS u
LEFT JOIN friend AS f ON uid=uid2
WHERE f.uid1='{$this->user}'
");
$arrayUsers = array();
// Create an array of just the ids
foreach($friends as $v){
$arrayUsers[$friend['uid']] = $v;
}
unset($friends);
// Create a string of these ids
$idstring = implode(",", array_keys($arrayUsers));
// Get the votes from only the users in that list that voted
$result = $this->db->query(
"SELECT vote, userid FROM user_votes WHERE userid IN ({$idstring})"
);
$result = array();
// Create a new result set (multi array). Include the data from the first
// Facebook query, but include only those who voted and append their votes
// to the data
while($v = $result->fetch_assoc())
{
if(isset($arrayUsers[$v['userid']])
{
$arrayUsers[$v['userid']] = $v['vote'];
$result[] = $arrayUsers[$v['userid']];
unset($arrayUsers[$v['userid']], $v);
}
}
return $return;
}

I can't tell you how your code would perform without measuring and testing. I would look for other issues with your code, that would make it a bit more readable/maintanable. For example:
Create smaller methods.
Inside the main method , I see some chunks of code that are well commented. Why not create a method instead of making a huge comment in the main method?
For example:
// Get The users friends that use this app from facebook
$friends = $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user"
);
return $friends;
Would make an interesting
functin get_users_friends_from_facebook($facebook){
// Get The users friends that use this app from facebook
$friends = $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user"
);
return $friends;
}
In the same manner,
// Get the votes from only the users in that list that voted
$result = $this->db->query(
"SELECT vote, userid FROM user_votes WHERE userid IN ($idstring)"
);
Is a good candidate to
function get_votes_from_voters(){
// Get the votes from only the users in that list that voted
$votes = $this->db->query(
"SELECT vote, userid FROM user_votes WHERE userid IN ($idstring)"
);
}
Give variables meaningful names to the context.
$return isn't a good name. Why don't you name it $users_votes for example?
Try to keep the naming convention of your plataform.
Check the apis you're using. Are they using camelCase? Are they using underscores? Try to keep with your libraries and plataform conventions. Check this topic for a good reference.
And welcome to SO. Your code is fine. Try to read some OO principles, you could even cut more lines of your code. All the simple advices I wrote here are avaiable in a great book named Code Complete.

I took points from all your comments and rewrote this method as below. Thanks for all the great input.
public function getAppUserFriends(){
global $facebook;
return $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user)
AND is_app_user;"
);
}
public function getFriendVotes(){
// Get the users friends that use this app
$friends = $this->getAppUserFriends();
// Create an array with the ids as the key
foreach($friends as $v){
$arrayFriends[$v['uid']] = $v;
}
// Create a string of these ids
$idString = implode(",", array_keys($arrayFriends));
// Get the votes from only the users in that list that voted
$result = $this->db->query(
"SELECT vote, userid
FROM user_votes
WHERE pollid=$this->poll
AND userid IN ($idString)"
);
// Pluck out user data from facebook array where the user has voted
// and add the vote to that array
while($row = $result->fetch_assoc()){
$friendsVotes[$row['userid']] = $arrayFriends[$row['userid']];
$friendsVotes[$row['userid']]['vote'] = $row['vote'];
}
return $friendsVotes;
}

Are you having performance troubles in this method? Because unless you are, there's no need to optimize it.
Code first, profile the code, and then optimize where it does the most good.

$friends = $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user"
);
could probably be shortened to
$userids = $facebook->api_client->fql_query(
"SELECT uid
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user)"
);
because the uid is the only thing you seem to be using from fb

It was a little hard for me to tell what you are trying to do, but you might consider looking at PHP's array_intersect (and its cousins).
A = {1:'fred', 2:'bob'}
B = {1: 2, 3: 0}
C = array_intersect( array_keys(A), array_keys(B) )
D = {}
foreach (C as c) {
D[c] = (A[c], B[c])
}
The syntax is off there but I hope it leads you in the right direction.

Related

SELECT a value multiple time in SQL

I have a code in PHP where I want to display multiple times values, and so, even if these values are the same between them. My code is simple :
$sql = "SELECT photo from table WHERE username IN ('1','2','2') ORDER BY id DESC ";
$res = array();
$result = mysqli_query($con,$sql);
while($row = mysqli_fetch_array($result)){
array_push($res, $row['photo']);
}
echo json_encode($res);
But this code only display (in json) an array of two values (because the values of photo of the username 2 are the same).
What I want to achieve is to make an array with the exact same number of values of the number of username I defined WHERE username IN ('1','2','2') (so here, 3 values).
I hope you understood me, thanks for helping me !
I think what you're after is to list even the duplicates in the end result. As your SQL will only retrieve the unique items, the idea would be to include the username in the SQL result set. Then use the original list of user names ($userNames) and add in the photo for each of them.
I've used mysqli_fetch_all() to simplify the process of fetching all of the data, then used array_column() to make the username the key for the photos.
$userNames = array(1,2,2);
$sql = "SELECT username, photo
from table
WHERE username IN ('".implode("','", $userNames)."')
ORDER BY id DESC ";
$res = array();
$result = mysqli_query($con,$sql);
$photos = mysqli_fetch_all($result, MYSQLI_ASSOC);
$photos = array_column($photos, "photo", "username");
foreach ( $userNames as $user ) {
if ( isset($photos[$user])) {
$res[] = $photos[$user];
}
else {
$res[] = '';
}
}
echo json_encode($res);
You would use left join:
select t.photo
from (select '1' as username union all select '2' union all select '3'
) u left join
table t
on t.username = u.username
order by t.id desc;
Note this will return rows, even when the user name does not exist. If you want to filter those rows, remove the left so you are doing an inner join.

else if condition while comparing 2 variables in php

I am new to php so far i wrote this referral script:
<?php
ob_start();
include( $_SERVER['DOCUMENT_ROOT'] . '/config.php' );
mysql_connect(DB_HOST,DB_USER,DB_PASS);
mysql_select_db(DB_NAME);
$id = $_REQUEST['id'];
$uid = $_REQUEST['uid'];
$oid = $_REQUEST['oid'];
$new = $_REQUEST['new'];
$total = $_REQUEST['total'];
$sig = $_REQUEST['sig'];
// Secrete Key
$hash = 'myapikey';
// Output results
if ($sig == $hash) {
//Users point update query here (it's working )
$users = mysql_query("SELECT points FROM users WHERE id=".$uid);
$rows = mysql_fetch_array($users);
$user_points = $rows['points'];
$query1 = mysql_query("update users set points=($user_points+$new) where id=".$uid );
//Updating referral coins (it's not working )
$query2 = ("SELECT points, referral_id, level FROM users WHERE referral_id=".$uid );
$user_rows = mysql_query($query2);
$all=mysql_fetch_array($user_rows,MYSQL_BOTH);
if($all['referral_id'] != 0 && $all['level'] == 0){
$lvl0 = $new*(15/100);
$referal_points = $lvl0;
$update_referral_points = ("update users set points = points + $referal_points where referral_id = ".$all['referral_id']);
mysql_query($update_referral_points);
} else if($all['referral_id'] != 0 && $all['level'] == 1){
$lvl1 = $new*(25/100);
$referal_points = $lvl1;
$update_referral_points = ("update users set points = points + $referal_points where referral_id = ".$all['referral_id']);
mysql_query($update_referral_points);
}
print "1\n";
} else {
print "0\n";
}
?>
How Script working:
whenever someone signup using referral code i have insert referral code user id into new user referral_id row, & through $_REQUEST['']; my app sending points ($new) to user...
$query1 is working fine there's problem to execute $query2, in short $query2 needs to be fixed; something getting wrong, that i am not able to figure out if any pro can help me out this i will appreciate it...
DB structure:
users table:
id (AI) name points Referral code Referral id Level
=========== ========== ========== ================== ============== ======
1 user A 0 abcdef123 0 0
2 user B 100 bvsuda897 1 1
3 user C 500 vrtasio65 2 0
In this example above,
1- user C signup using user B Referral code = bvsuda897
2- right now user B level is 1 so whenever user C earn point ($new) my app should give user B 25% coins of user C $new
The Problem
right now when my app sending coins to user C, user B not getting coins, because something wrong in query2
After spending some more time looking over your code, I have tracked down your issue. First, you need to get the referral_id from the $users query.
$users = mysql_query("SELECT points, referral_id FROM users WHERE id=".$uid);
Then $query2 needs to match the id to the user's referral_id, not the other way around.
$query2 = "SELECT id, points, referral_id, level FROM users WHERE id=".$rows['referral_id'];
Your UPDATE queries may need some work after that, but this will get you in to the if else conditions.
Successful code determined by OP
//Updating referral coins
$query2 = "SELECT id, points, referral_id, level FROM users WHERE id=".$rows['referral_id']; $user_rows = mysql_query($query2);
$all=mysql_fetch_array($user_rows,MYSQL_BOTH);
$lvl0 = intval((5/100) * $new);
$lvl1 = intval((10/100) * $new);
$query3 = mysql_query("update users set points = (points + $lvl0) where level = 0 AND referral_id = ".$all['referral_id']);
$query4 = mysql_query("update users set points = (points + $lvl1) where level = 1 AND referral_id = ".$all['referral_id']);
Now I appreciate that you are in the learning stage, but I want to point out a couple things that will cause confusions as you pursue PHP programming in the future.
First off, as Option mentioned, the MySQL functions you are using have been deprecated. They do not exist in the current stable version of PHP, and your code will no longer work if the server is updated. Look in to MySQLi or PDO as alternatives. It's a lot to learn, but some Googling will get you some guidance.
Second is your use of $_REQUEST, which combines the values of $_GET, $_POST and $_COOKIE, allowing easy manipulation by visitors. It may be that you are only using it for the user details while testing your other code, but I just want to make sure you know about PHP sessions, which is the better way to store a relationship between a logged in user and their persistent variables.

Search list of Facebook friends

I am trying to search a user's Facebook friends list against entries in a gamers table in an application database.
The gamers table looks like id, name, points. Eg. g_id-234567, name-john Smith, points-45. In this table a person's id, is actually their Facebook id.
I am using the following code in my Codeigniter application with the Facebook php sdk to return list of friends for the logged in user.
$friends = $facebook->api('/me/friends');
foreach ($friends["data"] as $value) {
echo $value['id'];
}
This code is in my index function of my controller, and it successfully echos the ids of all the friends of the logged in user.
How do I check if any of my Facebook friends id matches that of any gamer g_id in my gamers table.
I want to get the list of gamers who are my Facebook friends, and order this list in descending order of points witha limit of 20. This is to get the top 20 Facebook friends gamers.
I would like to use this list of the logged in user's top 20 Faccebook friends in my view.
Try this (If you are using mysqli)
$id = -1;
$list = array();
$stmt = $mysqli->prepare("SELECT * FROM gamers where id = ? ORDER BY points DESC LIMIT 20");
$stmt->bind_param("i", $id);
foreach($friends["data"] as $value) {
$id = $value['id'];
$stmt->execute();
$res = $stmt->get_result();
array_push($list,$res->fetch_row());
}
I hope, $list should contain the list of all facebook gamers.
Alternatively, you can use :
$friends_set = '(';
foreach($friends["data"] as $value) {
$friends_set .= $value['id'].',';
}
$new_set = preg_replace('/,$/',')',$friends_set);
$res = mysql_query("SELECT * from gamers WHERE id IN $new_set ORDER BY points DESC LIMIT 20");
while($row = mysql_fetch_array($res,MYSQLI_ASSOC) {
//do your stuff
}
Inside last loop you may traverse list of facebook gamers.

Check if usergroup exists

I have 2 variables which both hold comma separated lists. One is a permissions variable and the other is the usergroup list of the person wanting to access a page.
1 = user
2 = editor
3 = moderator
4 = admin
<?php
$query = mysql_query("SELECT * FROM users WHERE id='{$user['id']}'");
$user = mysql_fetch_assoc($query);
$query2 = mysql_query("SELECT * FROM menu WHERE active='1'");
$page = mysql_fetch_assoc($query2);
echo $user['usergroup']; // 1
echo $page['usergroup']; // 2,3,4
?>
I need help to find a way to compare both variables to check if they have the right usergroup to access a page
if $user['usergroup'] contains a number from $page['usergroup'] do X otherwise do Y
Thanks :)
$user = "1,3,5";
$page = "1,2,5";
//explode and trim for a case you have spaces '1, 2,3 ,4'
$u = array_map('trim', explode(",", $user));
$p = array_map('trim', explode(",", $page));
$intersect = array_intersect( $u, $p );
if ( count($intersect) )
{
//ok
print_r( $intersect );
}
else
{
//error
}
Allowed permissions:
Array
(
[0] => 1
[2] => 5
)
Try this:
$query = mysql_query("SELECT * FROM users WHERE id='{$user['id']}'");
$user = mysql_fetch_assoc($query);
$query2 = mysql_query("SELECT * FROM menu WHERE active='1'");
$page = mysql_fetch_assoc($query2);
$pageGroups = explode(',', $page['usergroup']);
if (array_search($user['usergroup'], $pageGroups) !== false) {
//TODO: User have access
}
Although I wouldn't store permissions as a commaseparated string, something like this might be what you are looking for:
$pageaccess = explode(',', $page['usergroup']);
if(in_array($user['usergroup'], $pageaccess)) {
// Has permissions. Code goes here.
}
edit: renamed $permissions to $pageaccess
While all the answers you got should work I'd like to add a comment to your approach. It's never a good idea to store comma seperated lists into your database. It offends the concept of database normalization.
Instead of storing comma seperated lists you should reconsider your database design. A possible approach could be:
users (user_id, username)
permissions(permission_id, permission)
user_permissions(up_id, permission_id, user_id)
That is much more efficient since you don't need to process the data that come from your database any further. You can just query your database and ask if the user has a certain permission.
SELECT `up_id` FROM `user_permissions` WHERE `user_id` = '{$uid}' AND `permission_id` = {5}
Taking this a step further you can assemble a little access control list:
users (user_id, username)
groups (group_id, name)
user_groups(ug_id, group_id, user_id)
permissions(permission_id, permission)
group_permissions(gp_id, group_id, permission_id)

Searching for unread posts in a database

Everytime a user reads a post, it assigns a cookie, eg.
set_cookies($id,'read',60*60*24);
But the problem is how do i select all the posts that hasn't been read by the user?
SELECT * from posts where (post is unread)
It doesn't require a login. Table structure:
ID | Content | Category
With your solution, you'd do something like this:
$ids = array();
if (isset($_COOKIES)) {
foreach ($_COOKIES as $cookie => $value) {
if (is_numeric($cookie) && $value == 'read') {
$ids[] = $cookie;
}
}
}
if (isset($ids[0])) {
$posts = implode(',',$ids);
$query = "SELECT * from posts where id in ({$posts})";
// Do the query
} else {
// no read posts.
}
But you should really look into storing your read variables differently.
I am assuming here that when user reads a post the id of the post read is stored somewhere. Let's for the moment assume that it is in the table read_posts that has a format:
UID | ID
In this case your query becomes:
SELECT * FROM posts WHERE ID NOT IN (SELECT id FROM read_posts WHERE uid = <user's id>);
If you only allow reading sequentially and store data in the same table the query becomes even simpler:
SELECT p.* FROM posts p, read_posts rp WHERE p.ID > rp.ID AND rp.UID = <user id>;
Syntax on this query might vary slightly but the general idea I think is clear.
If you can create a list of ids that have been read, yes:
SELECT *
FROM posts
WHERE ID NOT IN ($list_of_post_ids_that_have_been_read)

Categories