We use Varnish (likely to switch to Cloudflare) to cache the HTML of our pages. Occaisionally we would like to display a message to the user, which is flashed in the session: Session::flash('user_message', 'You cannot perform that action');.
The next page loads, and then there's an AJAX (to /ajax/message) call to check the server if there's a message to flash. Obviously the page load will absorb the flashed message, so what we've done in the BaseController is this:
if (Session::has('user_message') && !str_contains(Request::getPathInfo(), '/ajax/message')) {
Session::flash('user_message');
}
Our AJAX call simply states:
$response = [];
if (Session::has('user_message')) {
$response['user_message'] = Session::get('user_message');
}
return json_encode($response);
Which works, however, the next time a page loads, it will display the same message again! I've tried numerous things (such as Session::forget('user_message')) but to no avail. I'm at my wit's end to solve what should be a really trivial task. Does anyone know of a better way to do this or what's going wrong?
Thanks!
Related
I have a very special problem and I don't know how to deal with it.
I have web App in Laravel, when i open index page, I receive text message to my mobile phone.
Problem is, sometimes I receive 2 messages or 3, sometimes 1.
Is there a tool how to debug this strange behavior which is not always the same?
A few words about my code:
user opens the page, and because its first visit Session doesn't have attribute message_sent and SendTextMessage::SendMessage($phoneNumber, $id_message, $smsCode, $newDateFormat); is executed. After that Session has message_sent and can't be sent again, for example if I refresh the page.
SendTextMessage::SendMessage() is Class in Laravel Helpers.
controller code:
public function index($url_attribute, $id_message, Request $request)
{
if(!Session::has('message_sent'))
{
$user = User::where('id_message', $id_message)->first()->toArray();
$phoneNumber = $user['mobile_phone'];
$smsCode = $user['sms_code'];
$newDateFormat = date("d.m.yy", strtotime($smsExpirationTime));
$request->session()->flash('message', 'Text message sended.' );
SendTextMessage::SendMessage($phoneNumber,$id_message, $smsCode, $newDateFormat);
Session::put('message_sent', true);
}
return view('login');
}
SendTextMessage Class:
class SendTextMessage
{
public static function SendMessage($phoneNumber, $id_message, $smsCode, $newDateFormat)
{
$sms = new Connect();
$sms->Create("user","pass",Connect::AUTH_PLAIN);
$sms->Send_SMS($phoneNumber,"Message");
$sms->Logout();
}
}
Many thanks for any tip or help.
UPDATE:
problem is only in Chrome.
Edge and internet explorer are fine.
As this script runs on server-side the browser shouldn't be an issue. Based on your code provided, there is no clear answer to give here.
Please try the following in order to debug your problem:
Log messages at each stage of the script in order to see which part was called how often. That will help you to locate the problem. You can use \Log::error("Message") to do that.
Once you know where the problem might be, try to log "decision" making / mission critical variables to logile as well. E.g. \Log::error($session) so that you can understand why that problem might occur. One reason could be that you have a bad configured session caching or your cookies might be messed up. At some point there is probably a piece of data not the way you expect it to be.
You should maybe try to change the way you use Laravel Session.
You indicated that it was working fine on some browsers, that means your server-side code is correct so far, but there is someting messing with Chrome… From there,
if you take a quick look at the Laravel Session doc, you'll see that Session can be stored in cookies, and I bet that this is your actual setup (check in your .env file the SESSION_DRIVER constant, or in your config/session.php file).
If so, to confirm that this cookies-based session setting is the culprit, you might want to change the Session config to make it browser-independent: any other option than cookies will work, the database or file options might be the easier to setup… And if it works I would strongly encourage you to keep using this no-cookie setting to make your code browser-safe.
Im looking for an elegant way to hand over data/params when using $f3->reroute();
I have multiple routes configured in a routes.ini:
GET #sso: /sso/first [sync] = Controller\Ccp\Sso->first, 0
GET #map: /map [sync] = Controller\MapController->second, 3600
Now I reroute(); to #map route, from first();
class Sso {
public function first($f3){
$msg = 'My message!';
if( !empty($msg) ){
$f3->reroute('#map');
}
}
}
Is there any "elegant" way to pass data (e.g. $msg) right into $MapController->second(); ?
I don´t want to use $SESSION or the global $f->set('msg', $msg); for this.
This isn't an issue specific to fat-free-framework, but web in general. When you reroute, you tell the browser to redirect the user's browser page using a 303 header redirect code.
Take a minute to read the doc regarding re-routing: http://fatfreeframework.com/routing-engine#rerouting
There seems to be some contradicting information in your question, which leads me to question the purpose of what you are trying to achieve.
If you are rerouting, you can either use the session, cookies, or use part of the url to pass messages or references to a message.
If you do not need to redirect, but just want to call the function without changing the passed parameters, you could abstract the content of the function and call that function from both routes. You could also use the $f3 globals, which are a great way of passing data between functions in cases where you don't want to pass the data using the function call. is there a reason why you don't want to to use this? The data is global for the single session, so there is no security concern, and the data gets wiped at the end of the request, so there is very little extra footprint or effect on the server.
If you're alright with not using #map_name in re-routes you can do something like this:
$f3->reroute('path/?foo=bar');
Not the prettiest I'll admit. I wish $f3->reroute('#path_name?foo=bar') would work.
Is it a good practise, to use the php session object, to store several of my variables, can be arrays of request results.
I need this method, because I would like to do the request in a php file, store the result and immediately, (depending on result) redirect to a page,
It's probably not the best way, that's why I'm asking
thx for any advice,
edit: structure:
index.html
handler.php
view1.php
in index.html, I've got a
<form action="handler.php" ...
in handler.php, I construct a request and get a result,
if ($result->success)
header("location ./view1.php");
else
echo 'failed';
in view1.php, I would like to list the result array
Webshops do it - so why shouldn't you?
Some of the larger eCommerce frameworks store complicated data and objects in sessions and PHP handles this pretty well.
That's what sessions are for! So the general answer is "Yes: it's a good practice".
Here are some alternatives, however:
Consider using ajax calls to update parts of the loaded page without reloading it;
Cookies - not good for big amount of data, but generally can live longer than a session. Not useful in your particular case, however;
SQL servers are usually well-optimized, and when your query returns lots of rows and you cut those into sections with a LIMIT clause, or just repeat exactly the same request soon after the first time, the subsequent requests aren't of such a big load for the database server.
I just seen your update to the question.
AJAX can do the trick for you the best. I can imagine it all done within a single web page:
form data is submitted by an AJAX call to you handler.php, which..
returns either a JSON-packed array of results or a short string NOT FOUND, for example.
Then, the JS on your page either creates a new DOM element - a table, or a set of div's, with the returned results, or just creates a new div with some sad toon face and a "we didn't find anything' message.
// set session
session_start();
$_SESSION['my_session'] = array('var1' => 'value1', 'var2' => 'value2'); // your result list
session_write_close();
// get Session
echo ($_SESSION['my_sesson']['var1']);
if ($result->success)
header("location ./view1.php");
else
echo 'failed';
This is not good practice to use redirects to route requests. You can do it without additional request from the user.
Like this:
if ($result->success) {
include(dirname(__FILE__) .'/'. 'view1.php');
} else {
echo 'failed';
}
Thus, all variables from handler.php will be available in view1.php.
I am using Cakephp but this is a MVC/php doubt
letting the view display the message
vs
echo 'Invalid Data'; exit;
I would like to know is there any pitfalls in the second case like memory leak etc.. Which one is better
EDIT
In case of a ajax call is exit good. and what about memory leak and other issues . Are all variables deallocated
You should use a custom ExceptionHandler (set_error_handler / set_exception_handler) and throw an Exception if you encounter any errors (CakePHP should already provide an ExceptionHandler). Make some space in your view and if the ExceptionHandler/ErrorHandler has a message, show it there to let the user know.
Your second code will just produce a blank page containing the little text. Every user will appreciate if you show the message inside your usual page layout instead of producing a blank page (which looks broken to most people).
The Cake tools to signal errors to the user are session messages and error views.
For "passive" actions like view actions, you should throw a 404 or similar, possibly more specialized error, e.g. if the requested model does not exist:
function view($id) {
$data = $this->Model->read(null, $id);
if (!$data) {
$this->cakeError('error404');
}
...
}
See Error Handling with CakePHP.
For any POST action, you should return the user to the view and display an error message using $this->Session->setFlash('Error!') and appropriate error messages for each invalid form field. That's the default behavior of baked views and controllers.
Terminating the whole script with exit makes for a miserable user experience.
In general, you should avoid exit. Exit is an abnormal termination, and programs should not terminate abnormally. Even if an error occurs, there are still many things that needs to be done - cleanup, logging, notifying the user etc. After all, your operating system doesn't reboot every time it cannot open a file.
performance-wise (AJAX cals)
Use exit().
user experience-wise (standard site nav)
Show the error in a proper formated page keeping the user within your site.
I need to detect where the user has just clicked from - as my AJAX content needs to be displayed differently depending on the source page it is to be inserted into.
If it's to go into about.php it needs to be data only, but if it's to go into about-main.php it needs to be the whole middle column so needs a header/footer wrapper around the data.
The html called via AJAX is held in a php page which uses this code to see who's asking, and then formats the HTML response appropriately.
$array[] = "/cf/about.php";
$array[] = "/cf/about/about-main.php";
$array[] = "/cf/about/other-page.php";
$ispage = "";
foreach ($array as $value) {
if ($_SERVER['HTTP_REFERER'] != $value) {
$ispage = "";
} else {
$ispage = "woot";
}
}
if ($ispage == "woot") {
echo $content;
} else {
include_once 'about-header.php';
echo $content;
include_once 'about-footer.php';
}
The problem is... HTTP_REFERER seems to be a bit hit and miss. It works just fine while I'm at work on the network, but I've tried it out on my computer at home and it's obviously completely failing to work - the results are horrible :o
Is there another way of achieving this? I guess session variables could be used but then I've not got much experience of that!
Any and all hints/tips are appreciated ;)
Thanks!
edit:
The page is actually a staff profile page. Its normal location is about.php and the 2nd column div displays a grid of thumbnails which when clicked, load the profile in that place via AJAX. All nice and simple - back button reloads the grid of photos.
The problem is, each staff member also needs a static page. I've created these at about/staff-name.php. The content is THE SAME though. I want the server to detect if someone has come to the about/staff-name.php directly and if so, wrap a header/footer around it.
If the request has come from the grid of photos (ie AJAX) then it doesn't need the header/footer wrapper.
Is that clear? :o
1) If AJAX request - no wrapper
2) If not AJAX request - add header/footer wrapper
Wouldn't it be easier to just pass a flag in your AJAX call to tell the script which type of content to display?
Edit:
So about/staff-name.php displays the content. Call it via AJAX as about/staff-name.php?FromAjax=1
Then in the about/staff-name.php file:
if (isset($_REQUEST['FromAjax']) ) {
echo $content;
} else {
include_once 'about-header.php';
echo $content;
include_once 'about-footer.php';
}
No matter what, the Referer is not an information you should base your whole website upon : it is sent by the client, which means (at least) :
the client does not necessarily have to send it
it can be disabled in the browser
some firewall / antivirus remove it
it can be forged / altered (an easy way with firefox is to use an extension to do that)
You definitly must find a better/saffer/more reliable way to do what you need.
One solution (which you already discarded) would be to pass an additionnal information in all your links, saying which page the request comes from. In my opinion, this would probably be the best thing to do...
Maybe a simpler way would be to add a parameter to your Ajax request, saying where it comes from ? ie, instead of relying on the Referer in the PHP script, just have a look at a parameter in the request, which would act as some "kind of referer", but put by you ?
It will not be more secure (users could still forge request, with that parameter), but, at least, it would not be disabled / modified (except if the user does it by hand)
In the end, you also say this :
1) If AJAX request - no wrapper
2) If
not AJAX request - add header/footer
wrapper
Well, if it's only a matter of determining if the PHP script was called through an Ajax request, here too, two solutions :
Add a parameter to the Request when it's done through Ajax (you only add this parameter in the JS script doing the request ; and when the parameter is here, PHP knows it's an Ajax request)
Or, in the PHP script, look for an X-Requested-With HTTP header, which is often here with the value XMLHttpRequest when a request is made through an Ajax call. (But you should check that it's set with your JS Framework / or maybe it depends on the browser -- not sure about that :-( )
Why don't you just create the static pages on the server without using ajax at all, including the header and footer and the profile bit? If the page is static you shouldn't have any need to load content using javascript.
If you do need to load it using javascript, then Vex's solution is good. You could pass some optional parameters in the ajax call which control how the page is rendered - that way, the included page doesn't need to know about the pages that use it, it just needs to understand the parameters that tell it how to render itself. You can then reuse it more easily in future.
I did notice an error in your code however - this probably won't work as expected:
$ispage = "";
foreach ($array as $value) {
if ($_SERVER['HTTP_REFERER'] != $value) {
$ispage = "";
} else {
$ispage = "woot";
}
}
If a page name is matched, but then the next one isn't, $ispage will be set back to ''. You'd probably better off doing something like:
$ispage = "";
foreach ($array as $value) {
if ($_SERVER['HTTP_REFERER'] == $value) {
$ispage = "woot";
break;
}
}
or
$ispage = '';
if (in_array($_SERVER['HTTP_REFERER'], $array)) {
$ispage = 'woot';
}
Tai kucing -
If you format your links like this:
link
Then the php just needs to be this:
if (isset($_REQUEST['setvariablehere']) ) {
do something for when variable IS set
} else {
do something for when variable IS NOT set
}