Stackoverflow community! We've been struggling with this issue for a while now. We're attempting to upgrade our Laravel v4 site to Laravel v7. So far, it's been fine. When we use our login function, it properly authorizes the user, but upon redirect, the session gets killed. We've checked it over and over again, but we simply cannot find anything that could be the cause of the issue. Here is the suspect function:
public function loginv2()
{
if (Auth::check()) {
return Redirect::action('FrontController#showWelcome')->withMessage("Already logged in.");
}
if (!Auth::check() && !isset($_GET['token']))
{
$_SESSION['redirect'] = "https://zjxartcc.org";
header("Location: https://login.vatusa.net/uls/v2/login?fac=ZJX");
exit;
}
$token = $_GET['token'];
$parts = explode('.', $token);
$token = $this->base64url_decode($parts[1]);
$jwk = json_decode('{"alg":"HS256","use":"sig","kty":"oct","k":"..."}', true);
$algorithms = ['HS256' => 'sha256', 'HS384' => 'sha384', 'HS512' => 'sha512'];
if (!isset($algorithms[$jwk['alg']])) {
return Redirect::action('FrontController#showWelcome')->withMessage("Invalid Operation");
}
$sig = $this->base64url_encode(hash_hmac($algorithms[$jwk['alg']], "$parts[0].$parts[1]", $this->base64url_decode($jwk['k']), true));
if($sig == $parts[2]) {
$token = json_decode($token, true);
if($token['iss'] != 'VATUSA') {
return Redirect::action('FrontController#showWelcome')->withMessage("Not issued from VATUSA");
}
if($token['aud'] != 'ZJX') {
return Redirect::action('FrontController#showWelcome')->withMessage("Not issued for ZJX");
}
$client = new GuzzleHttp\Client();
$url = "https://login.vatusa.net/uls/v2/info?token={$parts[1]}";
$result = $client->get($url);
$res = json_decode($result->getBody()->__toString(), true);
$userstatuscheck = User::find($res['cid']);
if($userstatuscheck) {
if($userstatuscheck->status == 1) {
return Redirect::action('FrontController#showWelcome')->withMessage("You are not an active controller, and cannot login.");
} else {
Auth::login($userstatuscheck, true);
require("/home2/zjxartcc/public_html/forum/smf_2_api.php");
smfapi_login($userstatuscheck->id);
setcookie("ids_loggedin", $res['cid'], 0, "", ".zjxartcc.org");
$_SESSION['loggedin'] = $res['cid'];
}
} else {
return Redirect::action('FrontController#showWelcome')->withMessage("No user matching your information on the roster.");
}
//update email records and rating
$forum = SMFMember::find($res['cid']);
$forum->email_address = $res['email'];
$forum->save();
$member = User::find($res['cid']);
$member->rating_id = $res['intRating'];
$member->email = $res['email'];
$member->save();
return Redirect::action('FrontController#showWelcome')->withMessage('You have been logged in!');
} else {
return Redirect::action('FrontController#showWelcome')->withMessage("Bad Signature");
}
}
All help and suggestions are greatly appreciated! Thank you!
i am putting together a basic site with a basic shopping cart, we plan to store sensitive information in the sessions in the future so getting this sorted now is a smart choice.
Everything works fine without the custom session handler, for some context the session handling code is below:
function decrypt($edata, $password) {
$data = base64_decode($edata);
$salt = substr($data, 0, 16);
$ct = substr($data, 16);
$rounds = 3; // depends on key length
$data00 = $password.$salt;
$hash = array();
$hash[0] = hash('sha256', $data00, true);
$result = $hash[0];
for ($i = 1; $i < $rounds; $i++) {
$hash[$i] = hash('sha256', $hash[$i - 1].$data00, true);
$result .= $hash[$i];
}
$key = substr($result, 0, 32);
$iv = substr($result, 32,16);
return openssl_decrypt($ct, 'AES-256-CBC', $key, true, $iv);
}
function encrypt($data, $password) {
// Set a random salt
$salt = openssl_random_pseudo_bytes(16);
$salted = '';
$dx = '';
// Salt the key(32) and iv(16) = 48
while (strlen($salted) < 48) {
$dx = hash('sha256', $dx.$password.$salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32,16);
$encrypted_data = openssl_encrypt($data, 'AES-256-CBC', $key, true, $iv);
return base64_encode($salt . $encrypted_data);
}
class SecureSessionHandler extends SessionHandler {
protected $name, $cookie;
private $key;
public function __construct($key, $name = 'MY_SESSION', $cookie = [])
{
$this->key = $key;
$this->name = $name;
$this->cookie = $cookie;
$this->cookie += [
'lifetime' => 0,
'path' => ini_get('session.cookie_path'),
'domain' => ini_get('session.cookie_domain'),
'secure' => isset($_SERVER['HTTPS']),
'httponly' => true
];
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-
cbc'));
$this->setup();
}
private function setup()
{
ini_set('session.use_cookies', 1);
ini_set('session.use_only_cookies', 1);
session_name($this->name);
session_set_cookie_params(
$this->cookie['lifetime'],
$this->cookie['path'],
$this->cookie['domain'],
$this->cookie['secure'],
$this->cookie['httponly']
);
}
public function start()
{
if (session_id() === '') {
if (session_start()) {
return mt_rand(45, 99) === 55 ? $this->refresh() : true; // 1/5
}
}
return false;
}
public function forget()
{
if (session_id() === '') {
return false;
}
$_SESSION = [];
setcookie(
$this->name,
'',
time() - 42000,
$this->cookie['path'],
$this->cookie['domain'],
$this->cookie['secure'],
$this->cookie['httponly']
);
return session_destroy();
}
public function refresh()
{
return session_regenerate_id(false);
}
public function write($id, $data)
{
$data = encrypt($data, $this->key);
return parent::write($id, $data);
}
public function read($id)
{
$data = parent::read($id);
if (!$data) {
return "";
} else {
return decrypt($data, $this->key);
}
}
public function isExpired($ttl = 30)
{
$last = isset($_SESSION['_last_activity'])
? $_SESSION['_last_activity']
: false;
if ($last !== false && time() - $last > $ttl * 60) {
return true;
}
$_SESSION['_last_activity'] = time();
return false;
}
public function isFingerprint()
{
$hash = md5(
$_SERVER['HTTP_USER_AGENT'] .
(ip2long($_SERVER['REMOTE_ADDR']) & ip2long('255.255.0.0'))
);
if (isset($_SESSION['_fingerprint'])) {
return $_SESSION['_fingerprint'] === $hash;
}
$_SESSION['_fingerprint'] = $hash;
return true;
}
public function isValid()
{
return ! $this->isExpired() && $this->isFingerprint();
}
public function get($name)
{
$parsed = explode('.', $name);
$result = $_SESSION;
while ($parsed) {
$next = array_shift($parsed);
if (isset($result[$next])) {
$result = $result[$next];
} else {
return null;
}
}
return $result;
}
public function put($name, $value)
{
$parsed = explode('.', $name);
$session =& $_SESSION;
while (count($parsed) > 1) {
$next = array_shift($parsed);
if ( ! isset($session[$next]) || ! is_array($session[$next])) {
$session[$next] = [];
}
$session =& $session[$next];
}
$session[array_shift($parsed)] = $value;
}
}
$key = file_get_contents('./key.pem', FILE_USE_INCLUDE_PATH);
$session = new SecureSessionHandler($key);
ini_set('session.save_handler', 'files');
session_set_save_handler($session, true);
session_save_path(__DIR__ . '/sessions');
$session->start('cheese');
if ( ! $session->isValid(5)) {
$session->destroy('cheese');
}
There is the full session handler and encryption/decryption method, everything works fine overall but the problem is when going through my shopping cart code and changing all the $_SESSION variables into the $session->get objects, i managed to replace every $_SESSION then the last one i need to change throws a fatal error:
changing " $_SESSION['cart_contents'] = $this->cart_contents;"
to "$session->get('cart_contents') = $this->cart_contents;"
results in:
Fatal error: Can't use method return value in write context in C:\xampp\htdocs\teck\Cart.php on line 375
The rest of the important code is mentioned below, i made sure nothing was left out, its better to have a long post with all details than getting flamed for a small post with a question missing all details lol.
The page that you can adjust the quantity on is viewcart.php, the code thats important from this page is below:
<input type="number" class="form-control text-center" value="<?php echo
$item["qty"]; ?>" onchange="updateCartItem(this, '<?php echo
$item["rowid"]; ?>')">
and the script on the same page (viewcart.php) that throws the alert is below:
<script>
function updateCartItem(obj,id){
$.get("cartAction.php", {action:"updateCartItem", id:id, qty:obj.value},
function(data){
if(data == 'ok'){
location.reload();
}else{
alert('Cart update failed, please try again.');
}
});
}
</script>
Now finally cartaction.php, the code for the action "updatecartitem" is below:
}elseif($_REQUEST['action'] == 'updateCartItem' && !empty($_REQUEST['id']))
{
$itemData = array(
'rowid' => $_REQUEST['id'],
'qty' => $_REQUEST['qty']
);
$updateItem = $cart->update($itemData);
echo $updateItem?'ok':'err';die;
}
The update function thats in cart.php:
public function update($item = array()){
if (!is_array($item) OR count($item) === 0){
return FALSE;
}else{
if (!isset($item['rowid'], $this->cart_contents[$item['rowid']])){
return FALSE;
}else{
// prep the quantity
if(isset($item['qty'])){
$item['qty'] = filter_var($item['qty'],
FILTER_VALIDATE_INT);
// remove the item from the cart, if quantity is zero
if ($item['qty'] == 0){
unset($this->cart_contents[$item['rowid']]);
return TRUE;
}
}
// find updatable keys
$keys = array_intersect(array_keys($this-
>cart_contents[$item['rowid']]), array_keys($item));
// prep the price
if(isset($item['price'])){
$item['price'] = filter_var($item['price'],
FILTER_VALIDATE_FLOAT);
}
// product id & name shouldn't be changed
foreach(array_diff($keys, array('id', 'name')) as $key){
$this->cart_contents[$item['rowid']][$key] = $item[$key];
}
// save cart data
$this->save_cart();
return TRUE;
}
}
}
And last but not least the save_cart function in cart.php also:
protected function save_cart(){
$this->cart_contents['total_items'] = $this->cart_contents['cart_total']
= 0;
foreach ($this->cart_contents as $key => $val){
// make sure the array contains the proper indexes
if(!is_array($val) OR !isset($val['price'], $val['qty'])){
continue;
}
$this->cart_contents['cart_total'] += ($val['price'] * $val['qty']);
$this->cart_contents['total_items'] += $val['qty'];
$this->cart_contents[$key]['subtotal'] = ($this->cart_contents[$key]
['price'] * $this->cart_contents[$key]['qty']);
}
global $key;
global $session;
// if cart empty, delete it from the session
if(count($this->cart_contents) <= 2){
$session->forget();
return FALSE;
}else{
// original code below
$_SESSION['cart_contents'] = $this->cart_contents;
// code below is what i think will clear everything up but throws the
// error.
$session->get('cart_contents') = $this->cart_contents;
return TRUE;
}
}
The cart code above is in the same file as the session handler,
A bit more of an explanation, with " $_SESSION['cart_contents'] = $this->cart_contents;" (the original code),
i press the button +1 to add extra item into cart, the text field increases 1, and the error alert pops up saying "Cart update failed, please try again", i click ok and the alert goes away and nothing happens, the item qty in the text box stays updated but the actual real cart qty doesnt update until i refresh the page or click a link.
With the standard session handler in place this doesnt happen, everything works perfectly.
Is it a must that i change this $_SESSION['cart_contents'] variable to $session->get('cart_contents')?
I should be able to change that script alert to update the cart properly without throwing the alert but will my custom session handler work flawlessly if i leave that one session variable?
Im very sorry for the long post but i wanted to make sure everything is as clear as possible for other people to also understand if they are having similar problems.
The code does seem quite messy from this point of view but if you were to go over the entire site everything would make much more sense.
I have been on php for about 2 months max now trying my best to pick up as much as possible so please bear with me, obviously most of the code is not as clean as it should be, but this is production.
I have spent the past 3-4 days on this session handler, i really dont want to discard it and just go back to the standard _session.
All & any advice is welcome, constructive criticism will be taken lightly!
I really appreciate the time you have taken to go through this, Thanks for your effort!
You are getting the error at line
$session->get('cart_contents') = $this->cart_contents;
Here I assume the get function returns a reference. So if you want to store $this->cart_contents to the reference variable then you must use $$.
e.g $temp = $session->get('cart_contents');
and use $$temp = $this->cart_contents;
Or if you want to assign $this->cart_contents to the cart values then you must use
$this->cart_contents = $session->get('cart_contents');
You cant just use get method and assign a value to it.
Not much i could really do apart from keep researching, what ive done to get it working is below, but can someone please let me know if this will make my custom sessionhandler not work as intended?
i changed the updateCartItem function so there is no if statement just straight calls the function then reloads the page.
<script>
function updateCartItem(obj,id){
$.get("cartAction.php", {action:"updateCartItem", id:id, qty:obj.value},
function(data){
location.reload();
});
}</script>
This works fine with the save_cart function as below:
protected function save_cart(){
$this->cart_contents['total_items'] = $this->cart_contents['cart_total']
= 0;
foreach ($this->cart_contents as $key => $val){
// make sure the array contains the proper indexes
if(!is_array($val) OR !isset($val['price'], $val['qty'])){
continue;
}
$this->cart_contents['cart_total'] += ($val['price'] * $val['qty']);
$this->cart_contents['total_items'] += $val['qty'];
$this->cart_contents[$key]['subtotal'] = ($this->cart_contents[$key]
['price'] * $this->cart_contents[$key]['qty']);
}
global $key;
global $session;
// if cart empty, delete it from the session
if(count($this->cart_contents) <= 2){
$session->forget();
return FALSE;
}else{
$_SESSION['cart_contents'] = $this->cart_contents;
return TRUE;
}
}
BUT! Shouldnt the $_SESSION variable be replaced with my custom session handler call? ($session->get('cart_contents') = $this->cart_contents;) Obviously il get the error if i change it :(
Everything seems to work fine with the sessions, but will this create a weak point in my session security? And i should be able to use the if statement in the updateCartItem script! There must be a way to use the customsessionhandler call instead of "$_SESSION['cart_contents']".
I'm currently checking a Magento extension and I have a slight doubt about a piece of code. I would like you to explain. I understand all of it but not this one :
$customerID == " "
Is there a case where Magento have a customer id like that ( a space?) ?
Thanks a lot for your reply !
Here the entire function.
public function isAvailable(Varien_Event_Observer $observer)
{
$event = $observer->getEvent();
$method = $event->getMethodInstance(); //$method return the payment method
$result = $event->getResult(); //$result return true if method is active
$quote = $event->getQuote(); //$quote return var from cart
if($method->getCode() == 'custompayment' ){
//$customerGroup = $quote->getCustomerGroupId();
// $customerGroup="";
// $customerID="";
$login = Mage::getSingleton( 'customer/session' )->isLoggedIn(); //Check if User is Logged In
if($login)
{
$customerGroup = Mage::getSingleton('customer/session')->getCustomerGroupId(); //Get Customers Group ID
$customerID = Mage::getSingleton('customer/session')->getCustomerId(); //Get Customers ID
}
$selectedCustomerGroups = Mage::getStoreConfig('payment/custompayment/specificcustomers');
$selectedCustomerGroupsArray = explode(",", $selectedCustomerGroups);
if($selectedCustomerGroups != "" || $customerID == " "){
if(!in_array($customerGroup, $selectedCustomerGroupsArray)) {
$result->isAvailable = false;
}
}
else{
if($result->isAvailable==1){
$result->isAvailable = true;
}
}
}
Answered by adrien54 and JokiRuiz.
I am new in codeigniter and php.
I want to count post view number and store it database.
That means, I want to create a popular post plugin by counting post view.
But i can't do this.
Please anyone help me. Tell the way.
Here is my article Controller..
public function __construct(){
parent::__construct();
$this->load->model('article_m');
}
public function index($category_slug, $id, $slug=NULL){
// Fetch the article
$this->db->where('pubdate <=', date('Y-m-d'));
$this->data['article'] = $this->article_m->get($id);
$this->data['articles'] = $this->article_m->get();
// Return 404 if not found
count($this->data['article']) || show_404(uri_string());
if ($this->uri->segment(1) !== $this->data['cat']->category_slug) {
echo "Hi There, This is wrong";
}
$this->load->view('templates/article', $this->data);
}
}
Here is my Models:
public function get($id = NULL, $single = FALSE){
if ($id != NULL) {
$filter = $this->_primary_filter;
$id = $filter($id);
$this->db->where($this->_primary_key, $id);
$method = 'row';
}
elseif($single == TRUE) {
$method = 'row';
}
else {
$method = 'result';
}
if (!count($this->db->ar_orderby)) {
$this->db->order_by($this->_order_by);
}
return $this->db->get($this->_table_name)->$method();
}
Sorry for my bad english..
$post_id = "???"
if(isset($_COOKIE['read_articles'])) {
//grab the JSON encoded data from the cookie and decode into PHP Array
$read_articles = json_decode($_COOKIE['read_articles'], true);
if(isset($read_articles[$post_id]) AND $read_articles[$post_id] == 1) {
//this post has already been read
} else {
//increment the post view count by 1 using update queries
$read_articles[$post_id] = 1;
//set the cookie again with the new article ID set to 1
setcookie("read_articles",json_encode($read_articles),time()+60*60*24);
}
} else {
//hasn't read an article in 24 hours?
//increment the post view count
$read_articles = Array();
$read_articles[$post_id] = 1;
setcookie("read_articles",json_encode($read_articles),time()+60*60*24);
}
star complex to do?
//function single post, query get by slug and id post
if(!isset($_SESSION['views'. $id]) || (isset($_SESSION['views'. $id]) && $_SESSION['views'. $id] != $id)){
$this->post_m->viewer($id); //load model viewer
$this->session->set_userdata('views'. $id, $id);
}
// Model "post_m"
function viewer($id)
{
$this->db->where('id', $id);
$this->db->set('views', 'views+1', FALSE);
$this->db->update('posts'); //table update
}
$id is id post
Im currently creating my own forum for my website and i have read plenty of topics on cookie/session authentication and i think im aware of the attacks etc that exists. I get that its not 100% secure but im trying to do it as safe as possible.
Im currently storing IP in the cookie and im aware that some might have problems with that but im going to change to check the first 2 blocks of the IP instead. I dont think its going to be a problem since 95% of the people in Sweden got broadband which rarely changes IP.
Something that im really insecure about is the session_start which i do need later for forms etc what is the best practice to implement it? im pretty sure that im doing that thing pretty much wrong.
Any inputs is much appreciated!
Class
class user2
{
private $db = null;
private $cookie_salt = '!!PLonSIMDSAM35324dfg5DAUSHODNASDJ353NMASDSA&%&A/SD&HASNJDdfghAS&DGIHYAUSDNA3535SDFASDF%A3532dfgsdfggsdg53532535SDGIASYDU';
var $user_ip = false;
var $user_id = false;
var $user_username = false;
var $cookie_identifier = false;
var $user_logged_in = false;
function __construct()
{
global $mysql_server;
global $mysql_user;
global $mysql_password;
global $mysql_database_name;
$this->db = new database($mysql_server, $mysql_user, $mysql_password, $mysql_database_name, true);
$this->checkUserAuthentication();
}
public function Login($input_username, $input_user_password)
{
// If empty parameters return false
if (empty($input_username) || empty($input_user_password))
{
return false;
}
$user_login = $this->db->q("SELECT user_id, username FROM `forum_user` WHERE username = ? AND password = ? LIMIT 1", 'ss' , $input_username, $input_user_password);
if ($user_login != false)
{
$this->user_ip = $_SERVER['REMOTE_ADDR'];
$this->user_id = $user_login[0]['user_id'];
$this->user_username = $user_login[0]['username'];
if($this->initiateSessionCookie() == true)
{
$this->user_logged_in = true;
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
private function initiateSessionCookie()
{
// Delete old sessions from this user or USE REPLACE instead
$this->db->q("DELETE FROM `forum_session` WHERE userid = ?", 'i' , $this->user_id);
$identifier = md5($this->cookie_salt . md5($this->user_username . $this->user_ip) . $this->cookie_salt);
$token = md5($this->generateToken());
$timeout = time() + 60 * 60 * 24 * 7; // 7 days
$timeout_minutes = 10080; // 7 days
$init_session = $this->db->q("INSERT INTO forum_session SET session = ?
, token = ?
, userid = ?
, sess_start = now()
, last_activity = now()
, sess_expire = DATE_ADD(curdate(),INTERVAL ? MINUTE)
, ip = ?", 'ssiis' , $identifier, $token, $this->user_id, $timeout_minutes, $this->user_ip);
if($init_session != false) {
setcookie('auth', "$identifier:$token", $timeout);
return true;
}
else {
return false;
}
}
private function generateToken()
{
$chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz!#&";
for($i = 1; $i <= 20; $i++)
{
$rand_number = rand(0, 59);
$random_string .= $chars[$rand_number];
}
return $random_string;
}
private function checkUserAuthentication()
{
$this->user_logged_in = false;
list($_cookie_identifier, $_cookie_token) = explode(':', $_COOKIE['auth']);
if(ctype_alnum($_cookie_identifier) && ctype_alnum($_cookie_token))
{
$_cookie_data['identifier'] = $_cookie_identifier;
$_cookie_data['token'] = $_cookie_token;
}
else
{
return false;
}
$auth_user = $this->db->q("SELECT *
FROM forum_session a
LEFT JOIN
forum_user b ON a.userid = b.user_id
WHERE
a.session = ? AND
a.token = ?
LIMIT 1", 'ss' , $_cookie_data['identifier'], $_cookie_data['token']);
if($auth_user != false)
{
if(time() > strtotime($auth_user[0]['sess_expire']))
{
return false;
}
if($_cookie_data['identifier'] == md5($this->cookie_salt . md5($auth_user[0]['username'] . $_SERVER['REMOTE_ADDR']) . $this->cookie_salt))
{
$this->user_logged_in = true;
$this->user_id = $auth_user[0]['user_id'];
$this->user_username = $auth_user[0]['username'];
$this->user_ip = $_SERVER['REMOTE_ADDR'];
return true;
// TODO list
// Renew token every 5 min?
// Renew cookie expire date
// Renew session expire date
}
else
{
return false;
}
}
else
{
return false;
}
}
public function isUserLoggedIn()
{
return $this->user_logged_in;
}
}
The session handler which i include in all pages on the forum.
require_once('classes/user2.class.php');
$user = new User2();
session_start();
Why not start with session_start() in the controller(?).
If not needed always, I'd use a method in the controller so you avoid double session_start:
class controller {
$sStarted = false;
function sStart() {
if (!$this->sStarted) {
session_start();
$this->sStarted = true;
}
regards
/t