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.
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 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 a Beginner. Right now I am trying to build a simple Login/Register-System to learn.
It worked once, but not anymore and I cant figure out where im going wrong. Slowly my Code becomes Spaghetti.
What I want:
LOGIN-System that starts a Session after logging in. But the session is not working! Please beware that all the echos are ugly but just for me to check right now!
My HTML CODE:
//Check if class responds
$user->classtest();
session_start();
//Login-Function
if($user->checkSession()) {
echo "Session is okay";
} else {
if(isset($_POST['uname']) && isset($_POST['upass'])) {
$name = $_POST['uname'];
$pass = $_POST['upass'];
if($user->checkPW($name,$pass)) {
$user->startSession($name,$pass);
} else {
echo "Your Login is wrong, please try again";
$user->loginForm();
}
} else {
echo "<br>You are not logged in. Please login!";
$user->loginForm();
}
}
Here are the function from the classes:
Starting the Session:
public function startSession($uname,$upass) {
$userData = $this->getUserData($uname);
session_start();
$_SESSION['username'] = $userData[0]["username"];
$_SESSION['password'] = $userData[0]["password"];
echo "<br>You are logged in and we started the session ";
echo "<br>Username: " . $_SESSION['username'] . "<br>";
echo "<br>Password: " . $_SESSION['password'] . "<br>";
return true;
}
and my function that should check if there is a Session:
public function checkSession() {
if(isset($_SESSION['username']) && isset($_SESSION['password'])) {
return true;
} else {
return false;
}
}
Now, although my startSession function gives me the $_SESSION['username'] correctly after submitting the login-form the checkSession() Function always gives me false.
Sorry for the not perfect code etc. Im a real beginner still figuring things out!
You call checkSession BEFORE you ever call session_start(), which means $_SESSION will be empty, and your isset() calls will fail.
Just init the session with session_start(); on the top of your file.
Or - if necessary - in the construct function of your class:
function __construct() { session_start(); }
Please be aware of having output before initialise Session (or setting cookies also).
I'm sorry to trouble you, I have tried my best to solve this but I am not sure where I am going wrong and I was wondering if someone out there would be willing to help!
Basically, I am having some issues with $_SESSION variables; I would like for each occasion that a visitor came to the page that they would be shown a different content message.. The below code, when first landing on a page will seem to skip the first "content1", and will display "content2" instead, then "content3" after another revisit. I've put in an unset call, which eventually sends it there, am I not using _SESSIONS correctly?
I'm not sure how the session variable was assigned to 1, for it to land correctly in the if===1 statement without it first returning the original "content1"
if (empty($_SESSION)) {
session_start();
}
if (!isset($_SESSION['content'])) {
$content = "content1";
$_SESSION['content'] = 1;
return $content;
}
elseif ($_SESSION['content'] === 1) {
$content = "content2";
$_SESSION['content'] = 2;
return $content;
}
elseif($_SESSION['content'] === 2) {
$content = "content3";
unset($_SESSION['content']);
return $content;
}
Apologies for babbling or whether this was a simple fix / misunderstanding on my part. It's caused quite a headache!
Many thanks.
-edit-
This is a function that is called from within the same class, it has not gone through a loop anywhere either..
You are only calling session_start(); if the session has not been created.
What about the other times, when it's 1, or 2?
Call session_start(); regardless of your if (empty($_SESSION)) { statement
You should always use the session_start() function. If a session exists, it will continue it, otherwise it will create a new session.
Your code can then be simplified to the following:
// Start/Resume session
session_start();
// Get content
function display_message()
{
if ( ! isset($_SESSION['content']))
{
$_SESSION['content'] = 1;
}
if ($_SESSION['content'] == 1)
{
++$_SESSION['content']; // Increment session value
return 'Content #1';
}
elseif ($_SESSION['content'] == 2)
{
++$_SESSION['content']; // Increment session value
return 'Content #2';
}
elseif ($_SESSION['content'] == 3)
{
unset($_SESSION['content']); // Remove session value
return 'Content #3';
}
}
// Display content
echo display_message();
However, if someone visits your page a fourth time, they will be shown the first message again (because the session value is no longer tracking what they've been shown).
Perhaps this sort of functionality might be handled better with by using a cookie to track this information?
I'm sorry for the small amount of information, but there is not much else I can give you. The problem is, when trying to extend my login function to add an option for staying logged in, the cookies won't set. The session itself works (so there are no blank characters or something). I get no error messages, the cookie just doesn't set (tested with opera/firefox). After being puzzled for over an hour, i decided to ask it here. Below is the login function. Further down you will find how it's called. Don't worry about the password in the cookie, it's hashed. I tested if the code is in fact executed (placed an echo 'abc' before setcookie) which is the case.
public function login($password,$stayloggedin) {
if ( is_null( $this->id ) ) trigger_error ( "user::login(): Attempt to login an user object that does not have its ID property set.", E_USER_ERROR );
if ($this->compare_password($password))
{
if ($stayloggedin)
{
setcookie("userid", $this->id, time()+3600);
setcookie("userid", $this->password, time()+3600);
}
session_start();
$_SESSION['user_id'] = $this->id;
$_SESSION['user_name'] = $this->name;
$_SESSION['user_nummer'] = $this->user_nummer;
return true;
}
else
{
return false; //wrong password
}
}
This is how the above function is called.
<?php
header('Content-type: text/html; charset=UTF-8');
require_once 'required_script.php';
if (isset($_GET['login']))
{
require_once CLASS_PATH.'user.class.php';
$user_logging_in=new user();
$user_logging_in->load_from_name($_POST['user_name']);
if (isset($user_logging_in->id))
{
if ($user_logging_in->login($_POST['user_pass'],$_POST['remember_me']=='true'))
{
echo '1';
}
else
{
echo '0';
}
}
else
{
echo '2';
}
die;
}
Thanks a lot.
Your cookie won't set because you're outputting HTML headers before the log in / cookie setting functionality happens.
You can't pass any headers to the browser prior to creating the cookie.