I have a website where the front page contains a search form with several fields.
When the user performs a search, I make an ajax call to a function in a controller.
Basically, when the user clicks on the submit button, I send an ajax call via post to:
Route::post('/search', 'SearchController#general');
Then, in the SearchController class, in the function general, I store the values received in a session variable which is an object:
Session::get("search")->language = Input::get("language");
Session::get("search")->category = Input::get("category");
//I'm using examples, not the real variables names
After updating the session variable, in fact, right after the code snippet shown above, I create (or override) a cookie storing the session values:
Cookie::queue("mysite_search", json_encode(Session::get("search")));
And after that operation, I perform the search query and send the results, etc.
All that work fine, but I'm not getting back the values in the cookie. Let me explain myself.
As soon as the front page of my website is opened, I perform an action like this:
if (!Session::has("search")) {
//check for a cookie
$search = Cookie::get('mysite_search');
if($search) Session::put("search", json_decode($search));
else {
$search = new stdClass();
$search->language = "any";
$search->category = "any";
Session::put("search", $search);
}
}
That seems to be always failing if($search) is always returning false, and as a result, my session variable search has always its properties language and category populated with the value any. (Again: I'm using examples, not the real variables names).
So, I would like to know what is happening here and how I could achieve what I'm intending to do.
I tried to put Session::put("search", json_decode($search)); right after $search = Cookie::get('mysite_search'); removing all the if else block, and that throws an error (the ajax call returns an error) so the whole thing is failling at some point, when storing the object in the cookie or when retieving it.
Or could also be something else. I don't know. That's why I'm here. Thanks for reading such a long question.
Ok. This is what was going on.
The problem was this:
Cookie::queue("mysite_search", json_encode(Session::get("search")));
Before having it that way I had this:
Cookie::forever("mysite_search", json_encode(Session::get("search")));
But for some reason, that approach with forever wasn't creating any cookie, so I swichted to queue (this is Laravel 4.2). But queue needs a third parameter with the expiration time. So, what was really going on is that the cookie was being deleted after closing the browser (I also have the session.php in app/config folder set to 'lifetime' => 0 and 'expire_on_close' => true which is exactly what I want).
In simple words, I set the expiration time to forever (5 years) this way:
Cookie::queue("mysite_search", json_encode(Session::get("search")), 2592000);
And now it seems to be working fine after testing it.
Related
We have a CakePHP 3.x app which we've updated to the latest CakePHP 4.x. As part of this work we've also changed from PHP 7 to PHP 8.
Whilst testing the app we noticed a feature that had stopped working.
The app is a searchable database and is integrated with Redis for caching. One of the features means that the users search is retained between page reloads. This works by writing serialized form data to Redis, and then re-populating that back into the input fields in the template. This means the user sees the search criteria they entered; they do not need to re-enter their search criteria when the page is refreshed.
The code in the CakePHP 3.x app which re-populated the input form fields looked like this:
$form_fields = ['f1', 'f2', 'f3'];
The $form_fields array contains the names of the form input's in the template. As an example:
<input type="text" name="f1">
The next part of the code re-populates the form. In this case $user_search is an array of data that has been obtained and unserialized from Redis. As an example we might have $user_search['f1'] and $user_search['f3'] containing Redis data; f2 is unpopulated because the user didn't search using that field.
foreach ($form_fields as $form_field) {
$this->request->getData()[$form_field] = (isset($user_search[$form_field])) ? $user_search[$form_field] : '';
}
In the Cake 3.x app the above works fine. When the page is reloaded the form fields are set due to setting the request data, e.g. in the loop above, it evalulates to:
$this->request->getData()['f1'] = 'foo';
$this->request->getData()['f3'] = 'bar';
This means the request data has "foo" as f1 and "bar" as f3. There is nothing in f2 so it gets set to an empty string as per the : ''; condition.
In the CakePHP 4.x app this does not work; all form fields are unpopulated on page reload. I've confirmed that they are not being set to empty strings by modifying the : ''; condition mentioned above to : 'test'; and ensured the string "test" is not being shown in the fields.
The data exists in Redis and I've confirmed that $user_search contains what's shown above - in other words the data is not missing so we've ruled that out.
When I read over https://book.cakephp.org/4/en/controllers/request-response.html I can't see an example of setting request data. There is a method getData() which does what you'd expect - it reads the request data.
Is there a way to set the request data in Cake 4.x such that the above code would work?
In vanilla PHP what we're doing is equivalent to
$_POST['f1'] = 'foo';
$_POST['f2'] = ''; // empty string as no value set by user
$_POST['f3'] = 'bar';
AFAIK this was - and still is - valid in PHP; you can set/overwrite request data with anything in your code. If this is wrong please advise what I should be doing instead.
For clarity the reason we are setting request data in this manner is because the search for works via an ajax call. When the user enters their search criteria initially, the page has not been reloaded so the form fields appear to be populated correctly. This issue occurs on page reload. In that instance we want to repopulate the form with the values they entered prior to the page being reloaded.
The function you're looking for is withData. Remember that the request object is immutable, so you need to assign the result of that function call back into the request object, e.g. with $this->setRequest($this->getRequest()->withData('f1', 'foo')->withData('f3', 'bar')).
Hello CodeIgniter users.
I have a problem with flash data and I would like some help. My CI version is 2.1.4.
I am using CI flash data to store data temporarily for a form that consists of multiple pages. Data entered on each page is stored so it can be accessed on the next pages and finally all data is entered int the database.
Now to keep data stored through multiple pages, instead of only one, I extended the Session class with the following function:
function keep_all_flashdata($prefix = '')
{
$userdata = $this->all_userdata();
foreach ($userdata as $key => $value)
{
if (strpos($key, ':old:' . $prefix))
{
$new_flashdata_key = str_replace(':old:', ':new:', $key);
$this->set_userdata($new_flashdata_key, $value);
}
}
}
This function preserves all flash data (or optionally only flash data that starts with a certain string) for another redirect. It is similar to the keep_flashdata function except for the fact that it works for multiple items without requiring their exact name.
After calling this function, both :old: and :new: keys are stored in the session data. Then after a redirect, old keys are removed and new keys are set to old. Then, if there's another page, I call keep_all_flashdata() again and so on until the last page.
This works fine when I'm working on my local WAMP server, but on my actual server, all flashdata just gets removed after a redirect, even if it has :new: in the key. I confirmed my keep_all_flashdata() function works by checking the contents of session->all_userdata() and everything looks as expected.
I am using some AJAX calls, but they should not erase flash data (a known issue) as I've prevented this with $this->CI->input->is_ajax_request() before flashdata is cleared (in the sess_update() and _flashdata_sweep() functions).
Is this a bug in CodeIgniter or am I doing something wrong? Any help is appreciated.
I think your if statement is causing the problem. I'm assuming that ":old:" or ":new:" is used as prefix for every key you store in a session?
strpos() returns the position of where the needle exists so that would be 0 when checking a key with the prefix ':old:'. That's intended as old flashdata needs to be removed. I tested the following piece of code:
$flashDataKey = ':new:myKey';
die(var_dump(strpos($flashDataKey, ':old:')));
Which returns false as expected since the needle was not found. Resulting in not storing the flashdata as ':old:' and keeping it for the next request.
I'm not sure why this is working on your localhost. You should change your if statement to:
if( strstr($key, ':new:') !== false)
Now only keys containing the string ':new:' will pass and everything else will return false. Hope this helped!
Sorry if I'm duplicating threads here, but I wasn't able to find an answer to this anywhere else on StackOverflow.
Basically what I'm trying to do is make a list in which variables entered in a form by a user can be kept. At the moment, I have the code which makes this possible, and functional, however the variables entered in the form only appear on the list after the user hits submit... As soon as I refresh the page or go to the page from somewhere else, the variables disappear. Is there any way I can stop this from happening?
Edit: here are the codes:
//Page 1
<?php
session_start();
$entries = array(
0 => $_POST['signup_username'],
1 => $_POST['signup_email'],
2 => $_POST['signup_city']);
$entries_unique = array_unique($entries);
$entries_unique_values = array_values($entries_unique);
echo "<a href='Page 2'>Link</a>";
$_SESSION['entries_unique_values'] = $entries_unique_values;
?>
//Page2
<?php
session_start();
$entries_unique_values = $_SESSION['entries_unique_values'];
foreach($entries_unique_values as $key => $value) {
$ValueReplace = $value;
echo "<br /><a href='http://example.com/members/?s=$ValueReplace'>" . $value . "</a><br/>";
}
?>
Your question is really quite vague. the answer depends on how much data you have to store, and fopr how long you need it to exsist.
By variable I assume you mean data the user has entered and that you want to put into a variable.
I also presume that the list of variables is created by php when the form is submitted.
Php will only create the variable list when the form is submitted as php is done entirely on the server, therefore you will not have or see the variables until the form is submitted.
if you wanted to be able to see the list as it is being created you could use javascript then once you have you php variables the javascript list isn't necesary.
each time you request a php page wheather it is the same one or not the server generates a totally new page, meaning all unhardcoded variables from previous pages will be lost unless you continually post the variables around the pages the server will have no memory of them.
You have a few viable options.
) keep passing the user created variables in POST or GET requests so each page has the necesary info to work with. Depending on the situation it might or might not be a good idea. If the data only needs to exsits for one or two pages then it is ok, but bad if you need the data to be accessable from any page on your web.
2.) start a session and store the variables in a session. Good if the data only needs to be around while the user is connected to the site. but will be lost if user close window or after a time.
3.) place a cookie. not a good idea but ok for simple data.
4.) create a mysql database and drop the variable info in there. great for permanent data. this is how i always complex user data.
just a few ideas for you to look into as it is difficult to see what you really mean. good luck.
use PHP session or store variable values in Cookies via JS or using PHP. It would be nice if you show your working codes :)
Your idea is fine, however you just need to add a little condition to your Page 1 that only set your SESSION values when POST is made, that way it will keep the values even if you refresh. Otherwise when you visit the page without a POST those values will be overwritten by blank values, which is what you are seeing now. You can modify it like
<?php
session_start();
if(isset($_POST["signup_username"]))
{
$entries = array(
0 => $_POST['signup_username'],
1 => $_POST['signup_email'],
2 => $_POST['signup_city']);
$entries_unique = array_unique($entries);
$entries_unique_values = array_values($entries_unique);
$_SESSION['entries_unique_values'] = $entries_unique_values;
}
echo "<a href='http://localhost/Calculator/form2.1.php'>Link</a>";
?>
You could use JavaScript and HTML5 local storage.
One solution to automatically building navigation for a site is by scanning a folder for documents like this:
foreach(glob('pages/*.pg.php') as $_SITE_NAV_filePath):
$_SITE_NAV_filePath = explode('.pg',pathinfo($_SITE_NAV_filePath,PATHINFO_FILENAME));
$_SITE_NAV_fileName = $_SITE_NAV_filePath[0];
$_SITE_NAV_qv = preg_replace('/([A-Z])/','-$1',$_SITE_NAV_fileName); $_SITE_NAV_qv = trim($_SITE_NAV_qv,'-');
$_SITE_NAV_name = preg_replace('/([A-Z])/',' $1',$_SITE_NAV_fileName);
?>
<li><?=$_SITE_NAV_name?></li>
<?php
endforeach;
This code will turn "AnAwesomePage.pg.php" into a menu item like this :
<li>An Awesome Page</li>
This might be bad practice (?).
Anyway; I don't use this method very often since most of the time the sites have a database, and with that comes better solutions...
But my question is this:
Is there a way to prefix the filename with a integer followed by and underscore (3_AnAwesomePage.pg.php), for sorting order purposes, and pass it somehow to the destination page outside of the querystring and without any async javascript?
I could just explode the filename once again on "_" to get the sort order and store it somewhere, somehow?
This is the code for handeling the page query request:
$_SITE_PAGE['qv'] = $_GET['page'];
if (empty($_SITE_PAGE['qv'])){ $_SITE_PAGE['qv'] = explode('-','Home'); }
else { $_SITE_PAGE['qv'] = explode('-',$_GET['page']); }
$_SITE_PAGE['file'] = 'pages/'.implode($_SITE_PAGE['qv']).'.pg.php';
This code turns "An-Awesome-Page" back into "AnAwesomePage.pg.php" so it's possible to include it with php.
But with a prefix, it's not so easy.
The probliem is; Now there's no way to know what prefix number there was before since it has been stripped away from the query string. So I need to send it somehow along in the "background".
One very bad solution I came up with was to transform the navigation link into a form button and just _POST the prefix interger along with the form. At fist it sounded like a nice solution, but then I realized that once a user refreshes their page, it didn't look very good. And after all, that's not what forms are for either...
Any good solutions out there?
Or some other and better way for dealing with this?
There are two ways to keep that number saved, you can use cookies or php session variables.
But in this case, if user first enter the url in the browser or in a new browser, then he should be taken to default number.
Like you have:
1_first-page.php
2_first-page.php
3_first-page.php
If user enter the url like: domain.com/?page=first-page, you have to take him to 1_first-page.php to any number which you want to be default.
On my web page I have Zend_Form with CSRF hash. It submits to the same page and it is used to update user's data (name, surname, birthdate and so on...). I would like to reinitialize CSRF hash after every valid post submission. How I could do it?
Now when I first time submit 'user data' form I get proper behavior (user data gets updated). But if I submit again (right after first, proper submit) to change another form field I get error saying:
The two given tokens do not match
Is there anyway to reinitialize hash properly?
Your problem comes from this function in Zend_Form_Element_Hash the $session->setExpirationHops is set to 1 hop, so if you try to resubmit the same form it will always fail. This is by design and is the root of the security you're seeking.
However you can change this behavior, simply extend Zend_Form_Element_Hash and override this method to set the expirationHops to a value you prefer (you can also set the session options manually at any time if you prefer).
public function initCsrfToken()
{
$session = $this->getSession();
$session->setExpirationHops(1, null, true);
$session->setExpirationSeconds($this->getTimeout());
$session->hash = $this->getHash();
}
It goes without saying that it would be in the interest of security to perform a full refresh and repopulate the form to perform any edits. This should reset the hash.
My problem came from tampering with Zend_Form_Element_Hash init methods, I had this:
$_csrf = new Zend_Form_Element_Hash($this->_csrfName);
$_csrf->setSalt(md5($name));
$_csrf->setAttrib('id', '');
$_csrf->initCsrfToken();
The last line should never be there. When I removed it, everything started to act correctly.
#RockyFord: The initCsrfToken() function was place I was looking at the beginning, but
for me (I mean my intuition) it just couldn't be that. So I just debugged, debugged, debugged,
and at last commenting out 4th line was proper solution. Sorry for holding off reply, I totally forgot.