Json Syntax Error on Session Expire - php

I'm working with Slim Framework and I would like to redirect the user to the login page if the user has lost his session but I'm always getting a SyntaxError : Unexpected token < at position 0.
My session validation code in php is this:
private function _validaSessao() {
$user = $this->userData['IdUser'];
if(null === $user || trim($user) == '') {
header("Location: http://192.168.0.9/", true, 301);
die();
}
}
I've tried that and all the following:
header('refresh:5;url=http://192.168.0.9/');
echo '<script>window.location.href = "http://192.168.0.9/";</script>';
return('<script>window.location.href = "http://192.168.0.9/";</script>');
echo json_encode('<meta HTTP-EQUIV="REFRESH" content="0; url=http://192.168.0.9/">');
I've tried them all and I'm always getting
200 ---- SyntaxError: Unexpected token < in JSON at position 0
The only piece of code that worked for me was:
echo json_encode(array(
'SemSessao' => true
));
But the above code makes me checking on every single call on JavaScript and I would like a solution that PHP will redirect me. This way I wouldn't need to keep checking on every single JS call (which are a lot) and each time a php object was instanciated it would check for session and redirect the user without the use of JS.
Update 1 - Include JS code (lovely downvotes everywhere :D)
getDadosPlaneamento: function() {
var req = {Rota: '/planeamento/getDados/AUTO'};
var dfd = $.Deferred();
$.when(App.gajax(req)).done(function(d) {
On.Planeamentos = d.Planeamentos;
dfd.resolve();
});
return dfd.promise();
},
The above code is what refers to my php route and then:
$onapp->get('/planeamento/getDados/:tipo/', function($tipo) {
if ($tipo == 'AUTO') {
$P = new MongoApi\Planeamento();
$ret = array(
$P->getAllMongo();
);
}
echo json_encode($ret);
});
And when I do $P = new MongoApi\Planeamento(); I check if the user has a valid session on the constructor using _validaSessao();

The server cannot redirect a client from an AJAX call. The AJAX call is a background HTTP request. Whether that HTTP requests gets redirected or not is irrelevant to the browser. The browser will return the request response to the AJAX client, and if that response is "your request has been redirected" then that's that. Again, a redirect doesn't redirect "the browser", it redirects the HTTP request. Or more precisely speaking, it tells the HTTP client that it should retry its request somewhere else; nothing more.
If your AJAX requests can fail due to a session timeout and whenever that happens you want to present the user with a login page, you will have to do that client side. In order to not repeat that same code every time, you make a function/object/service out of that. E.g. something along the lines of:
function makeAJAXRequest(url, data) {
return fetch(url)
.then(response => {
if (response.status == 403) {
window.location = '/login';
throw new Error('Forbidden');
} else {
return response;
}
});
}
Here the server is expected to respond with a 403 Forbidden status code for unauthorised requests. If you make all your AJAX requests through this function, it will automatically handle that case by redirecting to the login page.

Remeber that header() must be called before any output is generated. you can use ob_start() and op_end_flush() to avoid output previous to your header.
ob_start ();
header ("Location: http://192.168.0.9/", true, 301);
ob_end_flush ();

Related

Put every POST and GET requests on hold except one specific, then continue

I need only PHP answers.
Setup : Apache Server and PHP version 7.4.
I'm working on a CAPTCHA plugin for WordPress. On that purpose, I thought I'd validate the CAPTCHA field before validating any other request.
This means I want to perform the CAPTCHA POST request before any other $_REQUEST is complete.
These other requests can be multiples, and I won't be able to handle their scripts.
I thought I'd detect if a POST or GET request has been made, then maybe call sleep() and perform my POST meanwhile.
The problem is : sleep() pauses the whole script whereas I only want the other POST and GET requests to be paused...
if ($_SERVER['REQUEST_METHOD'] === 'POST' OR $_SERVER[‘REQUEST_METHOD’] === 'GET' AND $_POST["myRequest"]) {
// Pause every POST and GET requests apart from $_POST["myRequest"] until $_POST["myRequest"] is performed
} else {
continue;
}
You could use session and keep track of the request and save the request if $_POST['myRequest'] is not present, than load the previous request from session or a file. Like this:
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST' OR $_SERVER[‘REQUEST_METHOD’] === 'GET') {
// POST myRequest has been done before
if(isset($_SESSION['.my-request.lock'])) {
// If present remove it
unset($_SESSION['.my-request.lock']);
if(isset($_SESSION['my-data.json'])) {
$my_prev_request = json_decode( $_SESSION['my-data.json'] );
unset($_SESSION['my-data.json']);
}
// Process other requests
} else {
if(isset($_POST['myRequest'])) {
$_SESSION['.my-request.lock'] = true;
// Do your own thing
} else {
// No myRequest and no file, save request data to load it after POST myRequest
$_SESSION['my-data.json'] = json_encode( $_REQUEST );
}
}
} else {
// Display Error ?
continue;
}

How do I redirect the user from within a getJSON call?

im receiving a json file from an external call. If the json comes with a null value (possible if the user session is expired) then the user should be redirected to the logout.php page. In my current call, instead of redirecting, the logout.php data is being received as a json response.
So, how do I redirect the user when the json data is null?
$.getJSON(sSource, aoData, function (json) {
if(json !== null) {
fnCallback(json);
} else {
window.location.href = "logout.php";
}
});
Thanks to #Ron's observation i noticed that, although sSource was calling the right file (datatables.php), its header isn't detecting the request method, hence returning the wrong data:
if(($_SESSION['login_expire'] + $session['expiration_time']) < time()) {
if($_SERVER['REQUEST_METHOD'] == 'POST') {
# forms
} else {
if(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
# datatable
header('Content-type: application/json');
echo json_encode(null);
} else {
# get
header('Location: '.URL_CMS.'logout.php?expired=true');
}
}
die();
} else {
# update expiration time
$_SESSION['login_expire'] = time();
}
That last bit controls idle times. It should also consider ajax calls, in which case it should return a json_encode(null) string instead of redirecting via php:
if(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
What you want is for your PHP to return some JSON that includes a response status and then use that response to send them to the error page if it's a bad status. For example, have your PHP return {"status":"failed", "message":"Expired"} instead of setting the Location header like it is currently.
Then in your Javascript:
if(json.status != "failed") {
fnCallback(json);
} else {
window.location.href = "logout.php";
}

can't make cross browser AJAX request to work

I am doing a simple ajax request to another domain like this:
<script type="text/javascript">
$(function() {
$('.clik').click(function() {
$.ajax({
type: "POST",
url: "http://sub.mydomain.com/test.php",
crossDomain: true,
dataType:"jsonp",
success: function(data) {
$('p.txt').html(data['no']);
}
});
});
});
</script>
</head>
<body>
<p class="clik">Halleluja</p>
<p class="txt"></p>
this is the test.php page on sub.mydomain.com
<?
header('Access-Control-Allow-Origin: http://mydomain.com');
// Begin Session
require_once('cl.session.php');
$session = new Session();
$session->start_session('test', false);
// Access Database
require_once('cl.database.php');
$login_db = new Database('user', 'pass', 'accounts', 'test');
$login_pdo = $login_db->PDO;
include "fn.check_login.php";
if(checkLogin($login_pdo) == true) {
// We start out by checking if the request has been made using AJAX
if (is_ajax()) {
echo "this is working";
} else {
echo "this is not working!";
}
} else {
echo 'You are not authorized to access this page, please login. <br/>';
}
// Function to check if the request is an AJAX request
function is_ajax() {
// BOOLEAN return if AJAX
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
}
?>
It returns a semantic issue.
Also if I simply echo some basic text:
<?
echo "Hello World!";
?>
it still returns a semantic issue.
could somebody tell me what went wrong?
Well, for a start, JSONP requests can't be POST (only GET). But I tend to assume jQuery is ignoring the invalid type. JSONP is intrinsically a GET.
Your response to it is invalid. You've told jQuery you're expecting the server to provide a JSONP response. but your responses aren't JSONP.
A JSONP response would look something like this:
callback({
"property": "value",
"anotherProperty": 42
})
...where the name of the callback (callback in the above) is taken from the query string of the request. So for instance, if the request were http://sub.mydomain.com/test.php?callback=foo, the response would use foo for the name of the callback:
foo({
"property": "value",
"anotherProperty": 42
})
jQuery will add the callback= query string parameter to the request for you automatically, and generate the corresponding function for you, which in turn calls the ajax success handler with the data passed into it.
I think you may need to use the jquery postMessage plugin (or similar if there is one). Long time since I tried it but check if you load the script from the server you wish to call (think I tried that and failed in the past but hey - its worth a bash - report back if it does).

How do you password protect a blogger post?

I've seen this question a number of times - just not here in SO. The answers to this point have all said to use use credentials in javascript (and we all know clientside credentials is no way to do authentication :)
The scenario is that I want to control a certain page on my blog - until such time as I let it loose to everyone. I have my own domain, so I can host php scripts. I've already tried Blogger's reader filter - it's great, but for viewers without a gmail account, it's a real pain in the
Here's my solution (using Javascript - but without user+password verification on the client). It's a hack - but I've got other fish to catch and miles to go before I eat.
The initial page call is this:
http://YOUR.DOMAIN.COM/manager.php?p=login
That prompts for the username and password
- ala this: http://www.php.net/manual/en/features.http-auth.php
After login some encryption is done on an authentication cookie
- ala this: http://php.net/manual/en/function.mcrypt-decrypt.php
- or this: http://php.net/manual/en/function.openssl-decrypt.php
The cookie is set
- ala this: http://www.php.net/manual/en/function.setcookie.php
And then the php file calls this present page via the following
- header('Location: http://YOUR2.DOMAIN.COM/p/page.html');
* YOUR2.DOMAIN.COM points to blogger; the page is this file here which will grab the file data and insert it into a div on the page
- see info here: http://support.google.com/blogger/bin/static.py?hl=en&ts=1233381&page=ts.cs
Based on the param and confirming that the cookie is valid, manager.php gets the real file data and sends it out
- ala this: http://php.net/manual/en/function.file-get-contents.php
Just drop the following into a blank Blogger page - taking care to replace the instances of YOUR.DOMAIN.COM
<script type="text/javascript" src="http://YOUR.DOMAIN.COM/scripts/jquery-1.8.3.min.js"></script>
<script type='text/javascript'>
var $pageUrl = "http://YOUR.DOMAIN.COM/manager.php?p=page1"; // so cool how you could setup your own domain!
function doInitStuff()
{
if ($alreadyInited) return;
$alreadyInited = true;
// a little hack - because though I said share cookies among (*) ".DOMAIN.COM" it wasn't getting sent
// although it's obviously there since we get it here on YOUR2.DOMAIN.COM (originally set on YOUR.DOMAIN.COM)
$cookies = document.cookie;
$result = $.ajax
({
type: "GET",
url: $pageUrl,
dataType: 'json', // or whatever
async: false, // force this to complete before moving on (should be quick though - since already logged in)
// username: 'username', // would get these from a prompt/html form - but should have already gone directly to the site to authenticate
// password: 'password', // did it that way, because wasn't able to get the u/p to be properly sent... this new way is better anyway
data: $cookies, // send along the cookies - they should show up in $_GET
success: function (result, status, jqXHR){
// good - but for some reason wasn't getting result - just move on...
},
error: function (){
// not good
}
});
if ($result.status == 200)
{
// insert our data into our nice Div
$('#realpageinfo').html($result.responseText);
}
// grrrrrr. ie strikes again! use iframes instead
var isMSIE = eval("/*#cc_on!#*/!1");
if ($('#realpageinfo').html() == '' || isMSIE)
{
//$('#realpageinfo').replaceWith("<div id='realpageinfo' style='font-weight:bold;color:red'>Internet Explorer? Sorry, but please use a different Browser.</div>");
$('#realpageinfo').replaceWith("<div id='realpageinfo'><iframe id='realpageframe' style='width:100%;height:700px' src='" + $pageUrl + "'></iframe></div>");
}
}
// Don't mind this - multiple ways to ensure the main worker function is called
var $alreadyInited = false;
$(document).ready(function() { doInitStuff(); });
window.addEventListener('DOMContentLoaded',function() { doInitStuff(); });
</script>
<div id='realpageinfo'></div>
Now for the server side
<?php
$cookieName = 'my_auth_cookie';
$loggedInCookieVal = $_COOKIE[$cookieName];
if (!isset($loggedInCookieVal))
{
$loggedInCookieVal = $_GET[$cookieName]; // was it passed in instead of coming through the Cookie channel?
}
// if $loggedInCookieVal is set, decrypt it and pull username + pwd from it - if succeeds, set $cookieValsDecrypted
// otherwise see if the user just sent them back in response to a challenge
// these are empty before login - and set in response to the challenge
$curUser = $_SERVER['PHP_AUTH_USER'];
$curPswd = $_SERVER['PHP_AUTH_PW'];
if (!$cookieValsDecrypted && (!isset($curUser) || !isset($curPswd)))
{
// ask the user to authenticate (again if have to)
header('WWW-Authenticate: Basic realm="YOUR.DOMAIN.COM"');
header('HTTP/1.0 401 Unauthorized');
echo "You gotta login bud - but you canceled instead";
exit;
} else {
// check $curUser and $curPswd against a db or .htpasswd file, etc - or check $cookieValsDecrypted
// if all good then send the file
if ($matched)
{
switch($_GET['p'])
{
case 'login': // just came here to login - now done, go on to the real page that pulls the value
header('Location: http://YOUR2.DOMAIN.COM/p/page.html');
break;
case 'page1':
echo file_get_contents ('./page1.txt'); // show the date
break;
}
} else {
// else send the auth request again
header('WWW-Authenticate: Basic realm="YOUR.DOMAIN.COM"');
header('HTTP/1.0 401 Unauthorized');
echo "Try something else, maybe";
}
}
?>
That's it... feel free to improve. See it in action here ClyntonCaines.Com

Ajax with tokens

How would you go about using tokens with the following?
$('#DIV').load('child.php?id='+id);
So that you couldn't access child.php straight from the browser and type child.php?id=1
If this is not possible with tokens would there be any other way?
Thought about XMLHttpRequest as follows:
var mygetrequest=new ajaxRequest();
mygetrequest.onreadystatechange = function(){
if (mygetrequest.readyState==4){
if (mygetrequest.status==200 || window.location.href.indexOf("http")==-1){
document.getElementById("DIV").innerHTML = mygetrequest.responseText;
} else{
alert("An error has occured making the request");
}
}
}
mygetrequest.open("GET", "child.php?id="+id, true);
mygetrequest.send(null);
Many thanks.
What you need is to check if the request is an ajax request (from load()) or not, this can be done by the following:
child.php:
if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
// it's an ajax request validate id and continue!
} else {
// this is not an ajax request, get out of here!
}
You could use jQuery post to send the parameters "behind the scene" and then check if the request was sent from a certain location or IP within the actual php file. If the location or IP does not have the authority to access it, simply output an error using e.g. the die() method before anything else has been output.

Categories