Laravel Socialite Facebook images are incorrect - laravel

I have a strange problem which I cannot figure out. I am using Laravel Socialite to allow login with Facebook account, there is a lot of users complaining that the profile image displayed on their account is incorrect, however the name etc is all fine.
It makes no sense to me as the name and the profile pic are pulled directly from FB at the same time.
public function socialUser(ProviderUser $providerUser)
{
$account = SocialFacebookAccount::whereProvider('facebook')->whereProviderUserId($providerUser->getId())->first();
if ($account) {
return $account->user;
} else {
$account = new SocialFacebookAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => 'facebook'
]);
$user = User::whereEmail( $providerUser->getId() )->first(); // changed from getEmail to getId as FB doesnt always give an email
if (!$user) {
$profilePicName = md5(rand(1,10000)) . ".jpg";
$contents = file_get_contents( $providerUser->avatar_original );
Storage::disk('local')->put( 'profiles/' . $profilePicName, $contents );
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
'profile_path' => $profilePicName
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}

Instead of using md5, you can use the UUID generator. One of the reasons for this problem because md5 generates the same hash for the same input. for instance, when you pass md5(111) it'll generate 698d51a19d8a121ce581499d7b701668. so if for a different user you generate the same hash key, the latest image profile will take a place and the former will replace by the latter.
Scenario:
User1:
$profilePicName = md5(111) . ".jpg";
$contents = file_get_contents( $providerUser->avatar_original );
Storage::disk('local')->put( 'profiles/' . $profilePicName, $contents );
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
'profile_path' => $profilePicName
]);
Scenario:
User2:
$profilePicName = md5(111) . ".jpg";
$contents = file_get_contents( $providerUser->avatar_original );
Storage::disk('local')->put( 'profiles/' . $profilePicName, $contents );
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
'profile_path' => $profilePicName
]);
Now they both have 698d51a19d8a121ce581499d7b701668.jpg saved in their profile. And in this case the first user profile will be the same as the second user image profile.

Related

Laravel avoid duplication between existing data and new inputs

I have an edit form where it shows users, sub-users and I need to make my update method the way that it can update existed sub-users as well as add new ones.
Logic
User can have a maximum of 5 sub-users
Let's assume my user already have 2 sub-users s/he can add up to 3 more
I want to be able to update those 2 that are existed already
I want to be able to add those 3 new sub-users
Code
Here is what I have currently. Code is commented for better understanding
public function subUsersUpdate(Request $request, $id) {
$will = Will::where('id', $id)->where('user_id', Auth::id())->first();
// main user
$user = User::where('id', $will->user_id)->first();
// making custom emails for new users like (admin1#example.com)
// admin is email name of main user, originally (admin#gmail.com)
// 1~5 are added to names (separate those 5 sub-users)
// example.com is website domain
$userMail = substr($user->email, 0, strpos($user->email, '#'));
$websiteName = env('DOMAIN_NAME');
// here is what I get from edit form including 2 existed sub-users and 3 new sub-users
foreach($request->input('subs') as $index => $sub) {
// trying to separate existed sub-users from new ones
$existedUser = User::where('name', $sub)->where('user_id', $user->id)->first();
if($existedUser) {
// if already existed just update the name
$existedUser->update(['name' => $sub]);
} else {
// if new add them as new sub-user
$num = $index+1;
$password = str_random(15);
User::create([
'name' => $sub,
'email' => $userMail . $num ."#" . $websiteName,
'password' => Hash::make($password),
'user_id' => $user->id,
]);
}
}
return redirect()->back();
}
Error
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'admin4#example.com' for key 'users_email_unique'
It appears that my code works in order to separate old and new sub-users but the problem is it makes the same email for new-users as old ones based on $num provided in my foreach. I need somehow avoid that duplication.
Any suggestion?
Update
What I did
I've added hidden input in my form which has sub-user email as value (if user existed) and if user is newly added it is null.
Then I merged those emails array and names array into one
Finally I've validate if the email field is null or not in order to update or create new sub-user.
Issue
Issue is name of all sub-users will be same as last input (sub-user 5), regardless of user being newly created or updated all 5 get same name!
public function subUsersUpdate(Request $request, $id) {
$will = Will::where('id', $id)->where('user_id', Auth::id())->first();
$user = User::where('id', $will->user_id)->first();
$userMail = substr($user->email, 0, strpos($user->email, '#'));
$websiteName = env('DOMAIN_NAME');
//Changed part
$mails = $request->input('mails');
$names = $request->input('subs');
// created array of data
$finalInputs = [];
foreach($mails as $index => $mmm) {
foreach($names as $index2 => $nnn) {
$finalInputs[$index] = ['email' => $mmm, 'name' => $nnn];
}
}
foreach($finalInputs as $index => $sub) {
if(!empty($sub['email'])) {
$existedUser = User::where('email', $sub['email'])->where('user_id', $user->id)->first();
$existedUser->update(['name' => $sub['name']]);
// $userMail2 = substr($sub['email'], 0, strpos($sub['email'], '#'));
} else {
if($sub['name'] != null) {
$num = $index+1;
$password = str_random(15);
User::create([
'name' => $sub['name'],
'email' => $userMail . $num ."#" . $websiteName,
'password' => Hash::make($password),
'user_id' => $user->id,
]);
}
}
}
// end of changed parts
}
Using updateOrCreate()
updateOrCreate() can handle conditional updating or creating of records for you.
This could be what you are asking, hope you get the idea:
foreach($finalInputs as $index => $sub) {
$pwHash = Hash::make( str_random(15) );
$num = $index+1;
$search = [
'user_id' => $user->id,
'email' => $userMail . $num ."#" . $websiteName,
];
$update = [
'name' => $sub['name'],
];
// Only add 'password' for new users
if (empty($sub['email']))) {
$update['password'] = $pwHash;
}
User::updateOrCreate(
$search,
$update
);
}
This will update or create users with the given email address and user-id and create if they don't exist. I don't know how your form works in detail, but I think you can adjust to your exact use-case.

in laravel if condition not working in controller

i am trying to use if condition in controller ( IF IMAGE NOT UPLOADED it go to ELSE condition Or else go to IF ) but it was not working , it just redirecting registration from page when submitting a form
code
public function Enrollment(Request $request)
{
$this->validate($request, [
'name' => 'required|string|max:255',
'father_name' => 'required|string|max:225',
'address' => 'required|string|max:255',
'card_id' => 'required|string|max:255',
'image' => 'required|image|mimes:jpeg,png,jpg',
]);
if ($request->image != '')
{
$input['name'] = strtoupper ($request['name']);
$input['father_name'] = strtoupper ($request['father_name']);
$input['address'] = strtoupper ($request['address']);
$input['card_id'] = strtoupper ($request['card_id']);
$input['image'] = time().'.'.$request->image->getClientOriginalExtension();
$folder1 = public_path('IMAGE/');
$path1 = $folder1 . $input['image']; // path 1
$request->image->move($folder1, $input['image']); // image saved in first folder
$path2 = public_path('IMAGE/BACKUP_IMAGE/') . $input['image']; // path 2
\File::copy($path1, $path2);
}else{
$input['name'] = strtoupper ($request['name']);
$input['father_name'] = strtoupper ($request['father_name']);
$input['address'] = strtoupper ($request['address']);
$input['card_id'] = strtoupper ($request['card_id']);
}
Card::create($input);
return back()->with('success','Enrolled Successfully.');
}
try this
if($request->hasfile('user_image'))
Nice that you use laravel. At first I will give you some hints to improve your code snippet.
You've written
it just redirecting registration from page when submitting a form
that's correct, because if you submit the form without an image, the validation will say "false".
You can't check an required in this way:
if ($request->image != '') {
because it's required.
Actually your code skips the validation at all, it would be better if you use the following:
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'father_name' => 'required|string|max:225',
'address' => 'required|string|max:255',
'card_id' => 'required|string|max:255',
'image' => 'required|image|mimes:jpeg,png,jpg',
]);
if ($validator->fails()) {
Session::flash('error', $validator->messages()->first());
return redirect()->back()->withInput();
}
If you dump your dd($validator); you will see all opertunities to validate the $request. Your errors you will find here: $validator->errors().
If something went wrong you should redirect back with the
->withInput()
so all data will stay in the form. Also possible with some explanation for the user ->withErrors():
// message information for the user
$messages = $validator->errors();
$messages->add('Your explanation');
// redirect
return redirect()->route('index')->withErrors($messages)->withInput();
Actually I am unsure why you save all $request in $input.
You can check https://laravel.com/docs/5.8/validation#using-rule-objects that for find an great solution for the strtoupper() usement.
Helpful links:
https://laravel.com/docs/5.8/validation
https://laravel.com/docs/5.8/session#flash-data

Satellizer Facebook Login 'Wrong Number of Segments error' LARAVEL

I have been playing with JWT Tokens lately, using Firebase\JWT and Satelizer.
I have been trying to integrate with laravel-angular project I have been working on.
Here is the sample code from Satelizers.io for facebook login: (https://github.com/sahat/satellizer/blob/master/examples/server/php/app/Http/Controllers/AuthController.php)
/**
* Login with Facebook.
*/
public function facebook(Request $request)
{
$client = new GuzzleHttp\Client();
$params = [
'code' => $request->input('code'),
'client_id' => $request->input('clientId'),
'redirect_uri' => $request->input('redirectUri'),
'client_secret' => Config::get('app.facebook_secret')
];
// Step 1. Exchange authorization code for access token.
$accessTokenResponse = $client->request('GET', 'https://graph.facebook.com/v2.5/oauth/access_token', [
'query' => $params
]);
$accessToken = json_decode($accessTokenResponse->getBody(), true);
// Step 2. Retrieve profile information about the current user.
$fields = 'id,email,first_name,last_name,link,name';
$profileResponse = $client->request('GET', 'https://graph.facebook.com/v2.5/me', [
'query' => [
'access_token' => $accessToken['access_token'],
'fields' => $fields
]
]);
$profile = json_decode($profileResponse->getBody(), true);
// Step 3a. If user is already signed in then link accounts.
if ($request->header('Authorization'))
{
$user = User::where('facebook', '=', $profile['id']);
if ($user->first())
{
return response()->json(['message' => 'There is already a Facebook account that belongs to you'], 409);
}
$token = explode(' ', $request->header('Authorization'))[1];
$payload = (array) JWT::decode($token, Config::get('app.token_secret'), array('HS256')); // STUCK HERE
$user = User::find($payload['sub']);
$user->facebook = $profile['id'];
$user->email = $user->email ?: $profile['email'];
$user->displayName = $user->displayName ?: $profile['name'];
$user->save();
return response()->json(['token' => $this->createToken($user)]);
}
// Step 3b. Create a new user account or return an existing one.
else
{
$user = User::where('facebook', '=', $profile['id']);
if ($user->first())
{
return response()->json(['token' => $this->createToken($user->first())]);
}
$user = new User;
$user->facebook = $profile['id'];
$user->email = $profile['email'];
$user->displayName = $profile['name'];
$user->save();
return response()->json(['token' => $this->createToken($user)]);
}
}
I am able to get the Facebook profile inforamtion, but I keep getting stuck on this line:
$payload = (array) JWT::decode($token, Config::get('app.token_secret'), array('HS256')); // STUCK HERE
It is throwing a 'Wrong number of segments' error when trying to read the taken set by satelizer.
I have inspected the token and it does not follow the typical JWT format. (there are no 'dots' in the token)
Has anyone expereinced this before? How do I go about solving this issue?
Thanks,
Matt

Update profile function

I have a function that check updates the users profile info. Currently, if I put |unique:users in the validator every time I try to update the profile info on the form it will not let me because a user (which is me) has my email. So I figured out the unique means that nobody, including the current user can have the email that is being updated.
So I need to compare the current auth email to the one in the database. If it matches then it is ok to update the profile info. I know this is simple but I am not sure how to implement it and if that is the right logic.
So where in this code would I post if (Auth::user()->email == $email){..update email...} http://laravel.io/bin/GylBV#6 Also, is that the right way to do this?
public function editProfileFormSubmit()
{
$msg = 'Successfully Updated';
$user_id = Auth::id();
$user = User::find($user_id);
$first_name = Input::get('first_name');
$last_name = Input::get('last_name');
$email = Input::get('email');
$phone_number = Input::get('phone_number');
$validator = Validator::make(Input::all(), array(
'email' => 'required|email',
'first_name' => 'required',
'last_name' => 'required',
'phone_number' => 'required'
));
if ($validator->fails()) {
return Redirect::route('edit-profile')
->withErrors($validator)
->withInput();
}else{
if(Input::hasFile('picture')){
$picture = Input::file('picture');
$type = $picture->getClientMimeType();
$full_image = Auth::id().'.'.$picture->getClientOriginalExtension();
if($type == 'image/png' || $type == 'image/jpg' || $type == 'image/jpeg'){
$upload_success = $picture->move(base_path().'/images/persons/',
$full_image);
if($upload_success) {
$user->picture = $full_image;
} else {
$msg = 'Failed to upload picture.';
}
}else{
$msg = 'Incorrect image format.';
}
}
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->email = $email;
$user->phone_number = $phone_number;
$user->save();
return Redirect::route('invite')->with('global', $msg);
}
}
Worry not, Laravel has already considered this potential issue! If you take a look at the docs for the unique validation rule you'll see that it can take some extra parameters. As it happens, you can give it an id to ignore when looking at the unique constraint. So what you need to do is work out the id for the current model to update and pass that in. In the case of updating a logged-in user's profile it's made easy by Auth::id() as you already have in your code.
$rules = [
'email' => ['required', 'email', 'unique:users,email,'.Auth::id()],
'first_name' => ['required'],
// etc...
];
Obviously I chose to use the array syntax for validation rules there, but you can do the same with the pip syntax too. In a less specific system (create-or-add in a crud postSave type action) you can still do it by simply dong something like $model = Post::find($id) and then if $model is null you're creating and you just use 'unique' whereas if $model is not null, use 'unique:table,field,'.$model->getKey().

custom phpbb3 registration

i am making a custom phpbb3 registration and i am trying to register a user form a external file but it not working . also i checked for errors . there is no error .can anyone help me out with where i am wrong . also if anyone has any easy idea how to add a new user record for phpbb3 please help me out with this .
<?php
$username = $_POST[username];
$password = $_POST[password];
$email_address = $_POST[email];
include('forums/common.php');
require('forums/includes/functions_user.php');
// Start session management
$user->session_begin();
$auth->acl($user->data);
$user->setup('viewtopic');
global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
$user_row = array(
'username' => $username, //REQUIRED IN FORM
'user_password' => md5($password), //REQUIRED IN FORM
'user_email' => $email_address, //REQUIRED IN FORM
'group_id' => 0,//(int) $group_id,
'user_timezone' => $timezone = date(Z) / 3600,//(float) $data[tz],
'user_dst' => date(I),//$is_dst,
'user_lang' => $user->lang_name,//$data[lang],
'user_type' => USER_NORMAL,//$user_type,
'user_actkey' => '',//$user_actkey,
'user_ip' => $user->ip,
'user_regdate' => time(),
'user_inactive_reason' => 0,//$user_inactive_reason,
'user_inactive_time' => 0,//$user_inactive_time,
);
// Register user...
$user_id = user_add($user_row);
?>
You must define
define('IN_PHPBB', true);
In other case your script will exit immediately in common.php and other required files. You can see
if (!defined('IN_PHPBB'))
{
exit;
}
in every required file

Resources