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!
Related
I am implementing a login controller, as it follows :
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
try {
session_start();
$datas = [];
$rqst = $request->getParsedBody();
if(!isset($_SESSION["login"]) ) {
if ((isset($rqst["email"]) && isset($rqst["pwd"]))) {
$loginRequest = LoginRequestFactory::from($request);
$loginId = $this->sessionService->connect($loginRequest);
if ($loginId != -1) {
$_SESSION["login"] = $loginId;
}
unset($_POST['email']);
unset($_POST['pwd']);
}
} else {
if (isset($rqst["logout"])) {
unset($_SESSION["login"]);
unset($rqst["logout"]);
}
}
$response = $response->withHeader('parsedBody', []);
$response->getBody()->write($this->rend($datas));
} catch (Exception $exception) {
$datas = [
'error' => $exception->getMessage(),
];
$response->getBody()->write($this->rend($datas));
}
return $response;
}
Everything works well concerning the login and the logout.
The problem is that, when the login request failed (from a login service, for example because login or password is invalid), an error is thrown from the service. This error is shown above the login form.
I want this error to disappear when I refresh the page. For that, I need to unset $_POST['email'] and $_POST['pwd'].
It doesn't work so I tried to do something like that, before returning the rendered response :
$response = $response->withHeader('emaill, '');
Or:
$reponse = $response->withoutHeader('email');
or:
$response = $response->withoutHeader('parsedBody[\"email\"]');
But nothing work, so when I refresh the page, the page ask me to repost the form and the error appears again.
I don't know if the problem is a PHP problem or if it can be solved with Slim functionalities, so has somebody an idea of how to unset posted datas when I do not need them anymore ?
Thanks a lot
I have found very strange behavior of "if" condition and session flashdata in codeigniter,
public function edit_equip($equip_id, $company_id) {
$this->data['section_title'] = 'Edit Equipment';
$this->data['equip_detail'] = $equip_detail = $this->common->select_data_by_id('equipment', 'id', $equip_id, '*', array());
if (empty($equip_detail)) {
$this->session->set_flashdata('error', 'Error Ouccrred. Try Again!');
redirect('Company/equipment/' . $company_id, 'refresh');
}
//some other code
$this->load->view('company/edit_equip', $this->data);
}
this is a function of my Equipment class. Now when I call below url like,
http://localhost/scale/Equipment/edit_equip/1/2
then edit view will open correctly. but now when I press F5 button or browser refresh button then it is showing "Error Ouccrred. Try Again!" flash message which I have set in above if condition. I am not understand why this is happening, because $equip_detail contains data and I have also try to die in it but it is not going into if which is correct so why only $this->session->set_flashdata('error', 'Error Ouccrred. Try Again!');
is providing effect?
in conclusion my code is not running if block but if i press F5 or browser refresh button after first time my view is loaded it is showing me error message which is set in if condition, but my code is not going to it otherwise it has to redirect but it is loading view page with flash message.
I have only set this flash message at only one place as per above code. I am using codeigniter 3.1.6
Please can anyone explain me this?
This isn't the solution, but more of an investigation to satisfy yourself how things are working...
So when things go "screwy", its always a good time to go back to basics. So seeing as you are so convinced your code is executing correctly but giving you unexpected results here is some test code just to check out the behavior of flashdata.
Flash_session_test.php
class Flash_session_test extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->library('session');
$this->load->helper('url');
}
public function index()
{
echo "This is " . __METHOD__;
$this->test_display();
}
/**
* Mockup code derived from sample code
* to test the behavior of the flash data.
*
* #param $equip_id
*/
public function edit_equip($equip_id)
{
echo "This is " . __METHOD__;
// Set up our Fail / Pass for the If statement below.
if (isset($equip_id)) {
if ($equip_id == 'fail') {
// Create a Fail Condition
$equip_detail = null;
} else {
// Create a Pass Condition
$equip_detail = array('fred' => 1);
}
}
// The code we are testing.
if (empty($equip_detail)) {
$this->session->set_flashdata('error', 'Error Occurred. Try Again!');
// Redirect and display the flashdata error message
redirect('/flash_session_test', 'refresh');
}
$this->test_display();
}
/**
* Our Test "View" put here for simplicity
*/
public function test_display()
{
echo '<br>';
echo '<a href="/flash_session_test/edit_equip/pass" >Click here to Create a PASS</a>';
echo '<br>';
echo '<a href="/flash_session_test/edit_equip/fail" >Click here to Create an ERROR</a>';
echo '<br>';
echo '<br>';
// Only display the message if we have one
$error = $this->session->flashdata('error');
if ($error === null) { // If null, then It doesn't exist
echo '<div style="color:green">';
echo "Not An Error in Sight!";
echo '</div>';
} else {
echo '<div style="color:red">';
echo $this->session->flashdata('error');
echo '</div>';
echo "Now Refresh the page!";
}
}
}
Note: This will run standalone, without relying on your existing code.
the CI manual says:
CodeIgniter supports “flashdata”, or session data that will only be
available for the next request, and is then automatically cleared.
F5 is sending a new request, so flashdata is cleared
Don't use $this->session->set_flashdata(), use $this->session->mark_as_flash() instead, it worked for me!
I was wondering, what's the best way to store messages for the user in PHP. With messages i mean something like
Authentication successful
or
Please enter a valid e-mail address
Currently I'm working on a project where they are stored in the $_SESSION variable, but I don't think this is a good solution.
Short explanation how I do it at the moment (The class Message was created by me)
$_SESSION["msg"][] = new Message("...");
and
foreach ( $_SESSION ["msg"] as $msg ) :
echo $msg->getText();
endforeach;
unset ( $_SESSION ["msg"] );
This is just a simplified version of the complete code, but you should get the idea.
EDIT: Forgot to say, that I'm working with an MVC framework and want to speperate the logic from the output.
One can only speculate on the nature/contents of your Message Class. However, here; attempt was made to simulate a mock-up of a class called Message; also the Usage in your View Script was shown below the Class. Be sure that $_SESSION is active on both Scripts.... Perhaps, this may shed some new light on how to go about your unique case:
<?php
//FIRST CHECK IF SESSION EXIST BEFORE STARTING IT:
if (session_status() == PHP_SESSION_NONE || session_id() == '') {
session_start();
}
class Message {
protected $msg;
public function __construct() {
if(!isset($_SESSION['msg'])){
$_SESSION['msg'] = array();
}
}
public function setText($message){
if(!in_array($message, $_SESSION['msg'])){
$_SESSION['msg'][] = $message;
}
}
public function getText(){
return "Some Logic for getting Message";
}
}
?>
<?php
// INSIDE OF YOUR VIEW SCRIPT; AT THE VERY TOP, ENABLE SESSION AS WELL:
//FIRST CHECK IF SESSION EXIST BEFORE STARTING IT:
if (session_status() == PHP_SESSION_NONE || session_id() == '') {
session_start();
}
// THEN LOOP THROUGH THE SESSION DATA FOR MESSAGES TO BE DISPLAYED
$msg = new Message();
if(isset($_SESSION['msg'])) {
foreach ($_SESSION ["msg"] as $msg) :
echo $msg->getText();
endforeach;
unset ($_SESSION ["msg"]);
}
I am having some trouble with setting up a pretty small application. It's going to be a little survey.
The form is split into two pages. After submitting the first one, the data is stored in the $_SESSION array with this:
save_items(array('my_data' => $my_data_oject));
The function save_items() looks like this:
function save_items(array $array) {
foreach ($array as $name => $item) {
$_SESSION[$name] = $item;
}
}
Then I unset($_POST) and redirect like this:
header('Location: index.php?action=survey_part2');
exit;
My problem is: After redirection, the previously stored login data is still in the $_SESSION, but my_data_object is not. If I avoid the redirection, I can see that my_data_object is stored in the $_SESSION array before the redirection starts. So the combination of header() and exit seems to destroy the session in part. Does anybody know how this can happen?
Finally, parts of my controller:
<?php
error_reporting(E_ALL);
session_start();
require_once 'models/functions.php';
require_once 'models/classes.php';
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : NULL;
$view = $action;
$language = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : 'de';
switch ($action) {
case 'login' :
if ((!empty($_POST['email'])) && (!empty($_POST['password']))) {
$user = new User();
$login = $user->find_user($_POST);
if (!empty($login)) {
set_message('Welcome ' . $login['Firstname'] . ' ' . $login['Lastname'] . '!');
save_items(array('user_id' => $login['CID']));
unset($_POST);
redirect("index.php?action=survey&lang=de"); //<- works fine. Login is kept, Message is kept.
} else {
set_message('Please try again.');
unset($_POST);
}
} else {
unset($_POST);
set_message('Try again.');
}
break;
/* ... shortage */
case 'survey' :
check_login(); //<- doesn't matter
if (empty($_POST)) {
/* ... shortage */
} else {
/* ... creation of my_data_object + setting one more message */
save_items(array('my_data' => $my_data_object));
unset($_POST);
save_items(array('test' => 'you see me?')); //<- index.php?action=survey_2 won't get it
//var_dump($_SESSION);
header('Location: index.php?action=survey_2&lang=de'); //<- does not work. Login is kept in $_SESSION, but not my_data
exit;
}
break;
Thanks!
This topic is maybe similar to that one here, but my $_SESSION is not empty after header(), but partly deleted.
Now I catched the problem. I tried to serialize a PDO with save_items() and after 1 day I've found the error message. My hint of the day: if you can, take a look into the php_error_log, because sometimes a very important error message is not shown on screen.
So my issue was relate to that one!
Solution: Put data as an Array into $_SESSION or use __sleep() and __wakeup() to specify which attributes (not: $db = new PDO();) should be serialized and which not.
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();
}
?>