FOR THE TL;DR VERSION...GO TO THE BOTTOM AND READ WHAT'S IN BOLD
OK, so I've had this problem for a while, and I've done a lot of research, made some changes and still have no idea what is wrong with my code. My problem is that when a user submits the registration form, the session always reverts back to empty. Here is how the logic goes:
1. The user navigates to mysite/register/ and is served with register.php by index.php in that same directory.
2. index.php handles everything (calls classes for the logic and things of that nature, but everything is run through index.php at the top level)
3. The user submits the login form through a vanilla.js ajax call and the response is console.logged back out.
Now that you understand the logic...let me get you to the code:
Here is index.php:
<?php
// Allowing PHP to be strictly typed and start session
declare(strict_types=1);
session_start();
// Requiring the necessary classes
require_once "../vendor/autoload.php";
require_once "../model/EditSession.php";
require_once "../model/DatabaseConfig.php";
require_once "../model/ServerValidation.php";
require_once "../model/RegisterUser.php";
require_once "../model/Verify.php";
// Creating the new objects
$validatingServer = new ServerValidation();
$sessionToEdit = new EditSession();
$sessionToEdit->create_new_session_id();
// Checks the request protocol
try {
$validatingServer->checkHttps();
} catch (Exception $ex) {
header("Location: /NotSecure.php");
}
// Setting CSRF token for protection
try {
$csrfToken = $sessionToEdit->store_secure_key_in_session("CSRFTOKEN");
} catch (Exception $ex) {
echo "You have a problem setting your session. $ex";
}
// Handling a navigation to the webpage
$validatingServer->navigateToWebsite("register.php", "Register", $csrfToken);
// For when a user submits the form
try {
$validatingServer->checkRequestType("POST");
$validatingServer->checkContentType("application/json");
$registerFormData = json_decode(file_get_contents("php://input"), true);
$csrfTokenFromForm = $registerFormData["csrfToken"];
$csrfTokenFromSession = $sessionToEdit->get_from_session("CSRFTOKEN");
} catch (Exception $ex) {
echo "Bad request data. $ex";
}
//$validatingServer->checkToken($csrfTokenFromForm, $csrfTokenFromSession);
// Call to make original register user object
try {
$register = new RegisterUser($registerFormData["firstName"], $registerFormData["lastName"], $registerFormData["email"], $registerFormData["password"]);
} catch (Exception $ex) {
echo $ex;
}
// Check email and register the user
try {
$register->checkEmail();
$register->register();
} catch (Exception $ex) {
echo $ex;
}
// Sending registration email to the user
try {
$register->sendRegistrationEmail("http://localhost/");
} catch (Exception $ex) {
echo $ex;
}
echo "Successful Register";
Here is the frontend
<!doctype html>
<html>
<head>
<title><?=$pageTitle;?></title>
</head>
<body>
<main>
<form id="registerForm">
<input type="text" id="firstName" name="firstName" autocomplete="given-name" placeholder="First Name" pattern="^[A-Za-z.\s_-]+$" autofocus required>
<input type="text" id="lastName" name="lastName" autocomplete="family-name" placeholder="Last Name" pattern="^[A-Za-z.\s_-]+$" required>
<input type="email" id="email" name="email" autocomplete="email" placeholder="Email" required>
<input type="password" id="password" name="password" placeholder="Password" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##\$%\^&\*]).{8,}" required>
<input type="hidden" id="csrfToken" value="<?=$csrfToken;?>">
<button type="submit" id="registerSubmit">Submit</button>
</form>
</main>
<script src="index.js"></script>
</body>
</html>
Here is index.js
const registerForm = document.getElementById("registerForm");
registerForm.addEventListener("submit", function(e) {
e.preventDefault();
const firstName = document.getElementById("firstName").value;
const lastName = document.getElementById("lastName").value;
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
const csrfToken = document.getElementById("csrfToken").value;
const registerFormData = {
"firstName":firstName,
"lastName":lastName,
"email":email,
"password":password,
"csrfToken":csrfToken
};
const ajax = new XMLHttpRequest();
ajax.open("POST", "index.php");
ajax.setRequestHeader("Content-Type", "application/json");
ajax.withCredentials = true;
ajax.send(JSON.stringify(registerFormData));
ajax.onload = function() {
console.log(this.response);
}
}, false);
Here is EditSession.php
<?php
declare(strict_types=1);
class EditSession {
private $firstPartOfNewId;
private $secondPartOfNewId;
private $thirdPartOfNewId;
private $newSID;
public $secureKey = "";
// Create new session ID
function create_new_session_id() : void {
if (isset($_SESSION)) {
$firstPartOfNewId = str_replace(array(".", ":"), "", $_SERVER["REMOTE_ADDR"]);
$secondPartOfNewId = round(microtime(true) * 1000);
$thirdPartOfNewId = hash("sha512", random_bytes(64));
$newSID = $firstPartOfNewId.$secondPartOfNewId.$thirdPartOfNewId;
session_id($newSID);
} else {
throw new Exception("Session is not set");
}
}
// Store a value in a set session
function store_in_session(string $key,string $value) : void {
if (!isset($_SESSION)) {
throw new Exception("Session is not set.");
}
if (!isset($_SESSION[$key])) {
$_SESSION[$key] = $value;
}
}
// Store a value in a set session
function store_secure_key_in_session(string $key) : string {
if (!isset($_SESSION)) {
throw new Exception("Session is not set.");
}
if (!isset($_SESSION[$key])) {
$secureKey = hash("sha512", random_bytes(64));
$_SESSION[$key] = $secureKey;
return $secureKey;
} else {
return $secureKey;
}
}
// Unsetting variable associated with the $key
function unset_session_variable(string $key) : void {
if (isset($_SESSION)) {
$_SESSION[$key] = "";
unset($_SESSION[$key]);
} else {
throw new Exception("Session with key is not set.");
}
}
// Getting associated key from session
function get_from_session(string $key) : string {
if (isset($_SESSION[$key])) {
return $_SESSION[$key];
} elseif (isset($_SESSION)) {
throw new Exception("Session is set, but the key passed is not set in the session.");
} else {
throw new Exception("Session is not set.");
}
}
}
?>
Here is ServerValidation.php
<?php
declare(strict_types=1);
class ServerValidation {
// Handles navigation to website
function navigateToWebsite(string $page, string $pageTitle, string $csrfToken) : void {
if (empty($_POST) && empty($_GET) && empty(file_get_contents("php://input"))) {
$csrfToken = $csrfToken;
$pageTitle = $pageTitle;
include_once $page;
exit;
}
}
// Checks if the website is served over https or its localhost
function checkHttps() : void {
if ($_SERVER["REQUEST_SCHEME"] !== "https" && $_SERVER["HTTP_HOST"] !== "localhost") {
throw new Exception("Not served over https");
}
}
// Checks if the content type is what it should be
function checkContentType(string $type) : void {
if ($_SERVER["CONTENT_TYPE"] !== $type) {
throw new Exception("Wrong content-type");
}
}
// Checks request method
function checkRequestType(string $type) : void {
if ($_SERVER["REQUEST_METHOD"] !== $type) {
throw new Exception("Wrong request method");
}
}
function checkToken(string $tokenFromFrontend, string $tokenFromSession) : void {
if ($tokenFromSession !== $tokenFromFrontend) {
throw new Exception("Tokens not matching up, there is a problem!!");
}
}
}
Now, here is what happens with the code. When the user submits the register form, with the csrfToken that is fetched from the hidden value in the form using AJAX, I get an exception thrown in my program (specifically from the checkToken() method in the ServerValidation class) that says "tokens not matching up". And I have confirmed why this is. If I var_dump the $_SESSION right after I call session_start(), it is ALWAYS empty. It doesn't matter if it has already been initialized (by the user first navigating to the page), it is ALWAYS empty. And so, following the logic of the program, it inserts a new value for CSRFTOKEN and so of course they don't match up. I am absolutely stumped and have been working on this problem for a week. Here are some answers to questions I know will be asked:
1. I'm using a macbook running XAMPP and php 7.2
2. My cookies are set to http_only, but not secure_only. All other cookie parameters are default.
3. My file permissions where my session data is being stored (/Applications/XAMPP/xamppfiles/temp/) is 777 (I just wanted to do something I know would work)
4. What happens if I don't create a new php session_id? The same outcome will happen...ie - the session will still always be initialized as empty
5. Can I var_dump the session at different points in the program? Sure...here are different points and their outcomes:
- Right after session_start is called:
- When the user initially navigates to the page: an empty session.
- When the user has submitted the registration form: an empty session
- Right after $csrfToken = $sessionToEdit->store_secure_key_in_session("CSRFTOKEN"); is called:
- When the user initially navigates to the page: a session with the key of CSRFTOKEN is returned
- When the user has submitted the registration form: a session with the key of CSRFTOKEN is returned (but the value is different than when the user originally navigated to the page)
- Right after $validatingServer->navigateToWebsite("register.php", "Register", $csrfToken);
- When the user initially navigates to the page: Nothing, because the program doesn't get that far because it exits out.
- When the user has submitted the registration form: a session with the key of CSRFTOKEN is returned (but the value is different than when the user originally navigated to the page and the value is different than what lives in the hidden field in the registration form)
Here is the question: Why do my session values keep initializing to empty, even though I'm on the same domain, doing all my work in the same file, have my session parameters set right, and have my file permissions set right?
Related
I'm trying to imitate the behavior of flash messages in native PHP, for one-time display of error messages.
Displaying the Login page:
public function showLoginAndRegistrationPage()
{
$session = new Session();
$data['errors']['login']['account'] = $session->getFormErrorFlashData('login', 'account');
$this->viewPresenter->display('basic', 'customer/login-registration', $data, 'Login/Register');
}
Verifying the login details:
public function processLogin()
{
// Some code
$session = new Session();
if($this->formInputFilter->isValid()) {
// Some code
if(true) {
// Some code
} else {
$errors = array(
'account' => 'Account does not exist.'
);
$session->setFormErrorFlashData('login', $errors);
header('Location: /login');
}
} else {
header('Location: /login');
}
}
For setting the error messages:
public function setFormErrorFlashData($form, $errors = array())
{
foreach($errors As $field => $message) {
$_SESSION['errors']["{$form}"]["{$field}"] = $message;
}
}
For getting the error messages stored in the session:
public function getFormErrorFlashData($form, $field)
{
if(isset($_SESSION['errors']["{$form}"]["{$field}"])) {
$message = $_SESSION['errors']["{$form}"]["{$field}"];
unset($_SESSION['errors']["{$form}"]["{$field}"]);
return $message;
}
}
Basically for an invalid attempt, after redirect, it should now display the 'Account does not exist' message, and then when the user refreshes the page, it should no longer be there.
What happens is when I comment out the unset() line in getFormErrorFlashData(), the $_SESSION contains the errors, but of course as expected they do persist even after countless page refreshes.
But when it's not commented out, I get a NULL. It seems that $message is also unset, even after attempting to store in it the value of that session key.
I have a bootstrap file that has the session_start() line, it's loaded for every page so I doubt that's the cause?
UPDATE:
index.php (bootstrap file)
<?php
session_start();
date_default_timezone_set('Asia/Taipei');
require_once 'core/Autoloader.php';
use core\Autoloader As Autoloader;
use core\Router As Router;
use core\Dispatcher As Dispatcher;
spl_autoload_register('core\Autoloader::loadClass');
$request_uri = trim($_SERVER['REQUEST_URI']);
$router = new Router();
$route = $router->handleRequest($request_uri);
if (!$route) {
require_once ('./views/errors/404.php');
} else {
$dispatcher = new Dispatcher($route);
$isDispatched = $dispatcher->dispatch();
if (!$isDispatched) {
echo '<div>' .$route['class'] .'/' . $route['action'] . ' not found </div>';
require_once ('./views/errors/404.php');
}
}
I've found the culprit.
When I traced the request logs, showLoginAndRegistrationPage() was being called twice because I didn't realize I also had a .js file attached in the html file with a submit event handler that gets fired too, thus the double page requests.
I removed the file and now it's working.
Thanks for the help!
I have a number of front-end functions which are triggered based on whether or not a user is signed in (i.e. the menu items displayed), but I'm having trouble triggering them when a user signs in unless they are redirected or the page is refreshed.
How can I change the value of $logged_in to be set once a user logs in? The functions are all working properly, including setting $_SESSION['SESS_USER_ID'] = $member['user_id']; once they're signed in.
Index.php (much of this code is also used throughout the site)
At the beginning of the document:
<?php
require_once('auth.php'); // This file starts session, and checks if(!isset($_SESSION['SESS_USER_ID']) || (trim($_SESSION['SESS_USER_ID']) == ''))
require_once('config.php'); // Connects to database connection
$user_id = $_SESSION['SESS_USER_ID'];
$logged_in = (isset($_SESSION['SESS_USER_ID']));
?>
The relevant functions are then triggered by $logged_in, and follow this basic format:
<?php if ($logged_in) : ?>
// Some HTML or Script
<?php else : ?>
// Some HTML or Script
<?php endif; ?>
Sign In form & function
My apologies if some of the AJAX is irrelevant - I don't really know AJAX and re-purposed existing code.
<form id="loginForm" name="loginForm" action="login-exec_pdo.php" method="post">
<label for="user_name">Username </label><input type="text" name="user_name" required />
<label for="password">Password </label><input type="text" name="password" required />
<div id="return_result"></div><div id="messageBox5">Please complete the highlighted fields</div>
<input type="submit" id="login" value="Sign in" />
</form>
<script type="text/javascript">
$(function () { $('#loginForm').validate({
rules: {user_name: {required: true, minlength: 2,}, password: {required: true, minlength: 6,},}, messages: {user_name: "", password: "",},
errorLabelContainer: "#messageBox5",
submitHandler: function (form){
$.ajax({
type: 'POST',
url: 'login-exec_pdo.php',
data: $("#loginForm").serialize(),
success: function(data) {
if(data == "true") {
$("#loginForm").fadeOut("fast");
}
else {
writeToTarget('return_result', 'Incorrect Username or Password');
} } }); } }); });
</script>
The login-exec.php file
<?php
session_start();
require_once('config/config_pdo.php'); // Includes db connection, salt, & PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION
$password = $_POST['password'];
$hashedPassword = sha1($salt . $password);
try {
$stmt_user = $conn->prepare("SELECT * FROM customer_info WHERE user_name = :user_name and password = :hashedPassword");
$stmt_user->bindValue(':user_name', $_POST['user_name'], PDO::PARAM_STR);
$stmt_user->bindValue(':hashedPassword', $hashedPassword);
$stmt_user->execute();
session_regenerate_id();
$member = $stmt_user->fetch();
if($member) {
$_SESSION['SESS_USER_ID'] = $member['user_id'];
$_SESSION['SESS_USER_NAME'] = $member['user_name'];
session_write_close();
echo "true";
exit();
}else {
echo "false";
exit();
}
}catch(PDOException $e) {
echo $e->getMessage();
}
?>
I've also tried using both javascript and php to set it in the success function within the Sign In function (where indicated above), but it either didn't set it and/or prevented the login function from completing properly. Some of the things I've tried are: if ($logged_in) : $logged_in = (isset($_SESSION['SESS_USER_ID'])); $logged_in = "true"; and $logged_in = 1;
If you're submitting the login request via AJAX, the main page's PHP won't be affected, since it's server-side and already written. If you're stuck on making the call through AJAX, you could:
1) Use the success() function to refresh the dialog/frame/whatever with the page that uses the $logged_in variable
2) Use the success() function to make another AJAX call to retrieve the page
3) Load everything (depending on how sensitive it is), but set the "logged in" material to display:none;, and use success() to do something like $('.logged-in-user-stuff').show();
Intro
It hurts my brain a bit, so let me show your obvious mistakes, first
Mistake #1
You can't set a PHP variable using JavaScript directly. This can done only by exchanging with JSON/XML
submitHandler: function (form){
$.ajax({type: 'POST', url: 'login-exec_pdo.php', data: $("#loginForm").serialize() ...
success: function(data) {
if (data == "true") {
$("#loginForm").fadeOut("fast");
// THIS IS WHERE I'VE TRIED TO SET $logged_in
// 1. You can't set $logged_in to true right from this point
// You should send JSON or XML back to PHP invoking a new nested ajax call
// and then parse that stuff in PHP and then send the parsed stuff back to JavaScript.
// However, this is some kind of bad approach, because A) you invoke a nested ajax call
// B) you make it even worse to debug and maintain C)
// 2. You serialized the form but never used it
....
Mistake #2
Mixed responsibilities and code duplication.
What exactly : Mixing database handler (including db configuration) with user responsibility (see descriptions below)
$stmt_user = $conn->prepare("SELECT * FROM customer_info WHERE user_name = :user_name and password = :hashedPassword"); <-- LIMIT 1 keyword should be appended
$stmt_user->bindValue(':user_name', $_POST['user_name'], PDO::PARAM_STR);
$stmt_user->bindValue(':hashedPassword', $hashedPassword); //<-- btw, you've missed PDO::PARAM_STR here
$stmt_user->execute();
...
session_regenerate_id(); //<-- This should be done after successful authorization, not before
$member = $stmt_user->fetch();
if($member) { //if you have error_reporting(E_ALL) you'll see a E_NOTICE
$_SESSION['SESS_USER_ID'] = $member['user_id'];
session_write_close();
echo "true"; //<-- Single quotes should be used instead of double ones.
exit();
}else {
echo "false";
exit();
}
So, ok. Assume that's a login page. But in a real-word scenarion, the profile page of the user would use a database as well.
According to your code, you would have to implement the same database handler twice or even more... (see comments below)
Mistake #3
No error tracking at all & rely on client-side validation.
Basically, you should never trust client-side validation, because anyone could just simply disable JavaScript in a browser.
And then he can easily send "invalid" data to the PHP script. Always do Server-Side validation!
But it does not mean that you should never use client-side validation at all.
Instead you should handle a situation when they come from browsers that do not have JS enabled/support.
You can try it yourself, just disable JavaScript in your browser and then enter your site...
Mistake #4
Not to mention the code duplication, the code itself isn't well structured. This is how this SHOULD NOT BE.
Here I'm saying about both JavaScript and PHP codes...
Now, how you should fix this
I'm not sure if you are going to follow above advices (in case you don't have a time or a will), so that let me answer your original question first.
How can I change the value of $logged_in to be set once a user logs
in?
In short: THIS IS A PHP VARIABLE ! And thus should be set in PHP
And it soulds like to me, even if you set $logged_in to TRUE once a user logs in, you've missed somewhere session_start().
Howewer, don't use this variable at all! Instead define a function, like, is_user_logged() because it's more reliable and "catchable" if something goes wrong.
Ok, next,
To make a life easier just define these functions:
/**
* Checks whether user logged in
*
* #return boolean TRUE if user is logged in
* FALSE if not
*/
function is_user_logged(){
//if session isn't started yet
if ( session_id() == ''){
// do start it now
session_start();
}
if ( isset($_SESSION['SESS_USER_ID']) ){
return true;
}
return false;
}
/**
* Retrieves an ID of the logged user if he's really logged
* NULL otherwise
*
* #return string|null
*/
function get_logged_user_id(){
if ( is_user_logged() === TRUE ){
return $_SESSION['SESS_USER_ID'];
}
return null;
}
/**
* "Marks" given user id as a logged one
*
* #return void
*/
function register_user_id_as_logged($id){
//will start session also if not started yet
if ( is_user_logged() !== TRUE ){
$_SESSION['SESS_USER_ID'] = $id;
}
}
Put these function at the top of the document.
Now change:
#1 in HTML template
<?php if ( TRUE === is_user_logged() ) : ?>
// Some HTML or Script if logged
<?php else : ?>
// Some HTML or Script if not logged
<?php endif; ?>
#2
...
$member = $stmt_user->fetch();
if($member) {
$_SESSION['SESS_USER_ID'] = $member['user_id'];
session_write_close();
echo "true";
exit;
to:
$member = $stmt_user->fetch();
if ($member) { //<-- Somehow my heart tells me it should be - if ( isset($member[0]) )
register_user_id_as_logged($member['user_id']); //<-- and this should be $member[0]['member_id']
session_regenerate_id();
exit('true');
if (data == "true") {
$("#loginForm").fadeOut("fast"); // <-- not required if you're going to do redirect
// THIS IS WHERE I'VE TRIED TO SET $logged_in <-- if you already in this "block", a "session id" is already set and it "works"
// all you need to do is just to redirect,like:
window.location = 'some_profile_page.php';
Now my own recomendations
Tip #1
Make sure the JavaScript isn't disabled.
You can simply do this, like,
<!DOCTYPE html>
<html>
<head>
...
<!--So, when JS is disabled, it would redirect to /error.php page automatically -->
<noscript>
<meta http-equiv="REFRESH" content="0; url=/error.php" />
</noscript>
...
</head>
...
</html>
Use this trick in all your HTML documents.
Tip #2
You should encapsulate all profile related logic into a class.
It should be similar to this one:
class Profile {
private $db;
public function __construct(PDOAdapter $db)
{
$this->db = $db;
}
public function login($username, $password)
{
//do query here and return boolean
}
public function logout()
{
//destroy session here
}
public function isLogged()
{
// check if session key exists and its a valid one here
}
private function registerAsLogged()
{
//....
}
}
I have some PHP code that creates a Facebook test account in my application using the graph api. I've tested this code out, and it works fine.
I'm having trouble actually logging into Facebook as the test user using Selenium Webdriver (for PHP).
Here's a simplified version of my code:
class FB_OAuthTest extends PHPUnit_Framework_TestCase {
private $fbUtils = null;
private $fbUser = null;
private $startUrl = 'http://my.start.page';
protected function setUp() {
$this->webdriver = new WebDriver(Config::SELENIUM_SERVER, Config::SELENIUM_PORT);
$this->webdriver->connect(Config::BROWSER);
$this->fbUtils = new FBUtils(Config::FB_APP_ID, Config::FB_APP_SECRET);
// create new FB test user here
$this->fbUser = $this->fbUtils->createNewTestUser();
}
protected function tearDown() {
// delete the test user when we're done
if($this->fbUser != null) {
$this->fbUtils->deleteTestUser($this->fbUser->id);
}
$this->webdriver->close();
}
// the magic happens here
public function testOAuth() {
// "login" as test user by requesting the login url that they give
$this->webdriver->get($this->fbUser->login_url);
// start the app workflow: go to a page with a FB OAuth button
$this->webdriver->get($this->startUrl);
$this->assertTrue(isTextPresent("FB_OAuth_Test_Start", $this->webdriver));
// click the button to begin the FB OAuth process
$oAuthButton = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//button[#control='FBLogin1']");
$oAuthButton->click();
// The Facebook login/OAuth dialog shows up now, and forces me to login
// despite first going to the FB user's login url
// sleep for the hell of it, just to make sure the FB login dialog loads
sleep(5);
// Selenium fails here - not finding the input with id='email', despite it existing on the page
$emailField = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[id='email']");
if ($emailField) {
$emailField->sendKeys(array($this->fbUser->email));
$emailField->submit();
} else {
$this->fail('FB login email field not found');
}
$passwordField = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[id='pass']");
if ($passwordField) {
$passwordField->sendKeys(array($this->fbUser->password));
$passwordField->submit();
} else {
$this->fail('FB login password field not found');
}
$loginButton = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[name='login']");
if ($loginButton) {
$loginButton->click();
} else {
$this->fail('FB login button not found');
}
$grantAppPermission = $this->webdriver->findElementBy(LocatorStrategy::name, "grant_clicked");
$grantAppPermission->click();
$this->assertTrue(isTextPresent("FB_OAuth_Test_Success", $this->webdriver));
}
}
As you can see from the code comments, Selenium can't find the 'email' input element, and the test fails. Any ideas would be greatly appreciated. Thanks!
Update
I've even tried doing something fairly direct, like the code blow, and it still doesn't work.
private function loginToFacebook() {
$this->webdriver->get('https://www.facebook.com/login.php?login_attempt=1');
sleep(1);
$emailField = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[id='email']");
if ($emailField) {
$emailField->sendKeys(array($this->fbUser->email));
$emailField->submit();
} else {
$this->fail('FB login email field not found');
}
$passwordField = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[id='pass']");
if ($passwordField) {
$passwordField->sendKeys(array($this->fbUser->password));
$passwordField->submit();
} else {
$this->fail('FB login password field not found');
}
$loginButton = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[name='login']");
if ($loginButton) {
$loginButton->click();
} else {
$this->fail('FB login button not found');
}
}
Update: Here's the Working Code
private function loginToFacebook() {
$this->webdriver->get('https://www.facebook.com/login.php?login_attempt=1');
$emailField = $this->webdriver->findElementBy(LocatorStrategy::id, 'email');
if ($emailField) {
$emailField->sendKeys(array($this->fbUser->email));
} else {
$this->fail('FB login email field not found');
}
$passwordField = $this->webdriver->findElementBy(LocatorStrategy::id, 'pass');
if ($passwordField) {
$passwordField->sendKeys(array($this->fbUser->password));
} else {
$this->fail('FB login password field not found');
}
$loginButton = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[#name='login']");
if ($loginButton) {
$loginButton->click();
} else {
$this->fail('FB login button not found');
}
}
You have defined ur xpath expression incorrectly
it should have been //input[#id='email'] ##Note the # sign (not sure you need to escape '#' with a blackslash)
But none the less try changing how you try to locate your web elements
// try locating by LocatorStrategy id
$emailField = $this->webdriver->findElementBy(LocatorStrategy::id, 'email');
if ($emailField) {
$emailField->sendKeys(array($this->fbUser->email));
$emailField->submit();
} else {
$this->fail('FB login email field not found');
}
It is quicker to search by id, name as compared to xpath.
make the same changes for password field as well, like so
$passwordField = $this->webdriver->findElementBy(LocatorStrategy::id, "pass");
Can anyone see a problem with this line: $emailtoken = md5($user['User']['password'].CAKE_SESSION_STRING);
As it gives the following error: Use of undefined constant CAKE_SESSION_STRING - assumed 'CAKE_SESSION_STRING'
It still creates a token but gives that error and then when using the token it says that it is invalid :/
Here is the full function:
function admin_resetpassword ( $token = null )
{
// User submits their email address
if (!empty($this->data['User']['email']))
{
// user submitted initial form
$user = $this->User->findByEmail($this->data['User']['email']);
if (empty($user))
{
$this->Session->setFlash('Unknown email.');
return;
}
else
{
$emailtoken = md5($user['User']['password'].CAKE_SESSION_STRING);
// send email (temp flash to test code)
$this->Session->setFlash($emailtoken);
return;
}
}
// If the token is not empty on the url
if (!empty($token))
{
$user = $this->User->find(array("MD5(User.password + '".CAKE_SESSION_STRING."')"=>$token));
if (empty($user))
{
$this->Session->setFlash('Invalid token.');
return;
}
if (!empty($this->data['User']['password']))
{
$user['User']['password'] = $this->data['User']['password'];
$this->user->save($user);
$this->Session->setFlash('New password set.');
$this->redirect('/');
}
$this->set('token', $token);
$this->render('newpassword2');
}
}
the problem is CAKE_SESSION_STRING is not defined (as stated in the error).
If you want to get the salt or cipherSeed, use Configure::read('Security.salt'); or $this-Session->id; But you know this session id is lost after certain inactivity period, right? You won't be able to get that session id back later on (unless you save it somewhere).
I'm having problems with a small OpenID-library called LightOpenID
.
I can authenticate to almost all providers, but I don't know how to fetch the data from the provider. I only get Array(), even with print_r().
You need to call getAttributes() after $openid->validate() not before.
Remember:
Note that it does not guarantee that any of the required/optional parameters will be present
This is how I use it. This is the file openid.php in the folder lightopenid. In the class make the following additional functions -
class LightOpenID
{
public $returnUrl
, $required = array()
, $optional = array()
, $verify_peer = null
, $capath = null
, $cainfo = null;
// these are the variables which store the data about the user...
public function ret_fname() { return $this->data['openid_ext1_value_namePerson_first']; }
public function ret_lname() { return $this->data['openid_ext1_value_namePerson_last']; }
public function ret_email() { return $this->data['openid_ext1_value_contact_email']; }
public function ret_lang() { return $this->data['openid_ext1_value_pref_language']; }
}
Now make your file example login.php which is called when you want to authenticate. There might be several copies of this file for different authentication domains etc.
<?php
# Logging in with Google accounts requires setting special identity, so this example shows how to do it.
session_start();
require 'lightopenid/openid.php';
include_once('config.php'); // initial setting file
try {
$openid = new LightOpenID; // akshat - declared an object of class lightopenid.. this is listed in openid.php
if(!$openid->mode) {
if(isset($_GET['login'])) {
$openid->identity = 'https://www.google.com/accounts/o8/site-xrds?hd=YourDomain.in'; //this can be changed as you know...
$openid->required = array('namePerson/friendly', 'contact/email' , 'contact/country/home', 'namePerson/first', 'pref/language', 'namePerson/last'); // akshat - line added by me from after reading from the net....
header('Location: ' . $openid->authUrl());
}
?>
<script type="text/javascript" src="js/jquery-1.4.2.min.js" language="javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
document.form.submit();
});
</script>
<form name="form" action="?login" method="post"> </form>
<?php
} elseif($openid->mode == 'cancel') {
echo 'User has canceled authentication for Your Domain !';
} else { // FETCH USER INFO HERE
$fname = $openid->ret_fname(); // fetching user first name...
$lname = $openid->ret_lname(); // fetching user last name...
$email = $openid->ret_email(); // fetching user email...
$lang = $openid->ret_lang(); // fetching user language...
session_start();
// use it as required. I set them in session !
$_SESSION['admin']['emailID'] = $email; //put email id in session.
$_SESSION['admin']['fname'] = $fname; //put first name also in session.
$_SESSION['admin']['lname'] = $lname; //put last name also in session.
$rurl = $_SESSION['redirect']; // you can ignore this. Go to your own page now...
header("Location:$rurl"); // Go back to the calling application !
}
} catch(ErrorException $e) {
echo $e->getMessage();
}
?>