6
\$\begingroup\$

I have an online catalog on which I need the customers to save their favorite products and shipping addresses. I want to manage the access with Facebook for security of all. I also need a section for the admin, to see some information in the database.

I want to know if this is safe. I want a basic "system" of user control and administration panel. I want to continue with the second part but I need to be sure that I'm going the right way.

entrar.php (login)

<?php
session_start();
date_default_timezone_set('America/Mexico_City');

// #################### Facebook config #################### //
require_once 'includes/facebook/autoload.php';

// Include required libraries
use Facebook\Facebook;
use Facebook\Exceptions\FacebookResponseException;
use Facebook\Exceptions\FacebookSDKException;

// Configuration and setup Facebook SDK
$appId                  = '123456789'; //Facebook App ID
$appSecret          = '123456789'; //Facebook App Secret
$redirectURL        = 'http://localhost/facebook/entrar.php'; //Callback URL
$fbPermissions  = array('email');  //Optional permissions

$fb = new Facebook(array(
    'app_id' => $appId,
    'app_secret' => $appSecret,
    'default_graph_version' => 'v2.5',
));

// Get redirect login helper
$helper = $fb->getRedirectLoginHelper();

// Try to get access token
try {
    if(isset($_SESSION['facebook_access_token'])){
        $accessToken = $_SESSION['facebook_access_token'];
    }else{
        $accessToken = $helper->getAccessToken();
    }
} catch(FacebookResponseException $e) {
    echo '<h3 style="color:red">Some problem occurred, please try again.</h3>';
    exit;
} catch(FacebookSDKException $e) {
    echo '<h3 style="color:red">Some problem occurred, please try again.</h3>';
    exit;
}

// #################### User class #################### //
require_once 'includes/meekrodb.php';

class User {
    function checkUser($userData = array()){
        if(!empty($userData)){
            // Check whether user data already exists in database
            $prevQuery = DB::query("SELECT * FROM usuarios WHERE id_fb = %s", $userData['id_fb']);
            $counter = DB::count();
            if($counter > 0){
            // Update user data if already exists
            DB::update('usuarios', array(
                'nombre' => $userData['nombre'],
                'apellido' => $userData['apellido'],
                'email' => $userData['email'],
                'genero' => $userData['genero'],
                'idioma' => $userData['idioma'],
                'imagen' => $userData['imagen'],
                'url' => $userData['url'],
                'modificado' => date("Y-m-d H:i:s")
                ), "id_fb = %s", $userData['id_fb']
            );
            }else{
            // Insert user data
            DB::insert('usuarios', array(
                'id_fb' => $userData['id_fb'],
                'nombre' => $userData['nombre'],
                'apellido' => $userData['apellido'],
                'email' => $userData['email'],
                'genero' => $userData['genero'],
                'idioma' => $userData['idioma'],
                'imagen' => $userData['imagen'],
                'url' => $userData['url'],
                'creado' => date("Y-m-d H:i:s"),
                'modificado' => date("Y-m-d H:i:s")
            ));
            }
            // Get user data from the database
            $result = DB::queryRaw("SELECT * FROM usuarios WHERE id_fb = %s", $userData['id_fb']);
            $userData = $result->fetch_assoc();
        }       
        // Return user data
        return $userData;
    }
}

// #################### Goo! #################### //
if(isset($accessToken)){
    if(isset($_SESSION['facebook_access_token'])){
        $fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
    }else{
        // Put short-lived access token in session
        $_SESSION['facebook_access_token'] = (string) $accessToken;

        // OAuth 2.0 client handler helps to manage access tokens
        $oAuth2Client = $fb->getOAuth2Client();

        // Exchanges a short-lived access token for a long-lived one
        $longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($_SESSION['facebook_access_token']);
        $_SESSION['facebook_access_token'] = (string) $longLivedAccessToken;

        // Set default access token to be used in script
        $fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
    }

    // Redirect the user back to the same page if url has "code" parameter in query string
    if(isset($_GET['code'])){
        header('Location:'.$redirectURL);
        exit;
    }

    // Getting user facebook profile info
    try {
        $profileRequest = $fb->get('/me?fields=first_name,last_name,email,gender,locale,picture,link');
        $fbUserProfile = $profileRequest->getGraphNode()->asArray();
    } catch(FacebookResponseException $e) {
        echo '<h3 style="color:red">Some problem occurred, please try again.</h3>';
        session_destroy();
        // Redirect user back to app login page
        header('Location:'.$redirectURL);
        exit;
    } catch(FacebookSDKException $e) {
        echo '<h3 style="color:red">Some problem occurred, please try again.</h3>';
        exit;
    }

    // Initialize User class
    $user = new User();

    // Insert or update user data to the database
    $fbUserData = array(
        'id_fb'         => $fbUserProfile['id'],
        'nombre'        => $fbUserProfile['first_name'],
        'apellido'  => $fbUserProfile['last_name'],
        'email'         => $fbUserProfile['email'],
        'genero'        => $fbUserProfile['gender'],
        'idioma'        => $fbUserProfile['locale'],
        'imagen'        => $fbUserProfile['picture']['url'],
        'url'           => $fbUserProfile['link']
    );
    $userData = $user->checkUser($fbUserData);

    // Put user data into session
    $_SESSION['userData'] = $userData;

    // Redirect and render facebook profile data
    if(!empty($userData)){
        header('Location: usuario.php');
        exit;
    }else{
        $output = '<h3 style="color:red">Some problem occurred, please try again.</h3>';
    }

}else{
    // Get login url
    $loginURL = $helper->getLoginUrl($redirectURL, $fbPermissions);

    // Render facebook login url
    $output = '<a href="'.htmlspecialchars($loginURL).'">Login with facebook</a>';
}

echo $output;
?>

usuario.php (user profile)

<?php
    // Activated the sessions
    session_start();

    // Render facebook profile data
    if(isset($_SESSION['userData'])){
        $userData = $_SESSION['userData'];
        echo '<h1>Perfil</h1>';
        echo '<img src="'.$userData['imagen'].'">';
        echo '<br/>Facebook ID : ' . $userData['id_fb'];
        echo '<br/>Nombre : ' . $userData['nombre'].' '.$userData['apellido'];
        echo '<br/>Email : ' . $userData['email'];
        echo '<br/>Genero : ' . $userData['genero'];
        echo '<br/>Idioma : ' . $userData['idioma'];
        echo '<br/><a href="'.$userData['url'].'" target="_blank">Ver perfil de usuario</a>';
        echo '<br/><br/><a href="salir.php">Salir</a>';
    }else{
        echo "Please login";
    }
?>

admin.php (admin area)

<?php
    // Activated the sessions
    session_start();

    // Check for admin
    if(isset($_SESSION['userData'])){
        $userData = $_SESSION['userData'];
        if ($userData['id_fb'] === 'MY_FB_ID_PROFILE') {
            echo "You are admin!";
        }else{
            echo "You are not admin";
        }
    }else{
        echo "Please login";
    }
?>

salir.php (Get out)

<?php
// Activated the sessions
session_start();

// Remove access token from session
unset($_SESSION['facebook_access_token']);

// Remove user data from session
unset($_SESSION['userData']);

// Redirect to the homepage
header('Location: index.php');
exit;
?>
\$\endgroup\$
0
1
\$\begingroup\$

At the beginnig: im providing this answer for PHP 7.2. You should switch to the latest version (7.3 was released days ago. Also 7.0 will reach EOL soon). Keep in mind to stick to the latest or LTS version. Also please use english only in your code. Namings in Mexican/French/Spanish/German and s.o. will decrease your maintainablility heavily.

Okay let's start with entrar.php:

  1. please use autocode formatting : $appId = '123456789'; //Facebook App ID. Many IDEs are providing this feature like PHPStorm
  2. set $appId and $appSecret values as const. They wont change. You can also think about moving them into an seperate class just containing public consts.
  3. Your try-catch statement is ok but you can also catch multiple Exception types in one catch statement.
  4. Don't just check for isset. The valuie can be still empty. Better use empty(). empty will check for isset and not empty and not 0 and so on. The PHP_docs are explaining this very well.
  5. Please avoid class definitions in your business logic e.g. class User {. Better move them into an own file/class-file for better maintainability.
  6. function checkUser($userData = array()){ at first add a scope like public/protected/private. Then also provide a return type as with >= PHP 7.0 type hinting became more important. Don't worry., it's just to support you as developer and maintainer.
  7. 'nombre' => $userData['nombre'], NEVER EVER trust the userinput. This is the number one security leak in modern architectures. Please add some validation
  8. Avoid GET requests e.g. if(isset($_GET['code'])){. They are not secure. Better use POST instead

Next usuario.php

  • Like i mentioned above: Don't trust the user input! NEVER EVER (I can't repeat it enough). You receive your data from $_SESSION and the sessiondata itself are safe but please keep it in mind anyway.

The rest is ok (regarding the code itself) I wont comment on your architecture because i dont have enough background information on your project. But keep focusing on it, you are on a good way.

\$\endgroup\$
0
\$\begingroup\$

First I recommend you to use a framework like symfony, laravel, silex, etc.

In entrar.php, you are doing different things, please move them to readable separated files.

For admin users, you can easily add an is_admin column and stores it in session instead of using your profile id.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.