Very strange $_SESSION behaviour - php

I have a Session which I am using to hold items in a form that are accumulated up by the user until the user wants to proceed to checkout. Its a bit like a Shopping cart where items can be added from the form.
Logical breakdown of code:
Page loads, session starts
If $_SESSION['set'] is not set then set it to TRUE.
Display rest of page and form.
User hits "Add another item" button.
Page data gets posted to itself
Page checks that $_SESSION['set'] = True and $_POST['add_item'] is set.
Page creates a session variables in an array, and adds posted values to those sessions.
Page increments $_SESSION['tariff_count'] if more needs to be added
The problem is that my code is not behaving as it should. When I click "Add new tariff" button the first time it does not get caught by my if function. This should be immediately caught. However when I go and press the button again, it finally works and adds an item to my session.
Here is the code:
//start a session to remember tariff items
session_start();
//testing the session array
print_r($_SESSION);
//destroy session if this character is found in URL string
$des = $_GET['d'];
if($des == 1)
{
session_destroy();
}
//checks to see if session data has been set
//if a session variable count is set then
if ($_SESSION['set'] == TRUE)
{
//perform a check to ensure the page has been called by the form button and not been accidently refreshed
if(isset($_POST['add_tariff']))
{
//if user clicks Add another tariff button then increase tariff count by one
//temp variable set to the current count of items added
$count = $_SESSION['tariff_count'];
$_SESSION['tariff_name'][$count] = $_POST['tariff_name'];
$_SESSION['tariff_net'][$count] = $_POST['tariff_net'];
$_SESSION['tariff_inclusive'][$count] = $_POST['tariff_inclusive'];
$_SESSION['tariff_length'][$count] = $_POST['tariff_length'];
$_SESSION['tariff_data'][$count] = $_POST['tariff_data'];
//increment tariff count if more data needs to be added to the sessions later.
$_SESSION['tariff_count']++;
}
}
//if no session data set then start new session data
else
{
echo "session set";
$_SESSION['set'] = TRUE;
$_SESSION['tariff_count'] = 0;
}
The code seems to be fudging my arrays of Sesssion data. All my added items in the session are displayed in a table.
However if my table shows six items, if i do a print_r of the session it only shows there are 4 items in the array? I have tested it to make sure I am not reprinting the same instances in the array.
Here is a print_r of the array that shows six rows but there are only four rows in this array?
[tariff_count] => 5 [tariff_name] => Array (
[0] => STREAM1TARIFF [1] => STREAM1TARIFF [2] => CSS [3] => CSS [4] => CSS
)
I have take a screenshot as well to show this strange problem
http://i.imgur.com/jRenU.png
Note I have echoed out "True Value =6" but in the print_r of the session it is only 5, so my code is missing out one instance (n-1).
Here is my code that prints all the instances in the session arrays, I have a feeling part of the problem in mismatch is caused by the "<=" comparison?
if(isset($_SESSION['tariff_count']))
{
for ($i = 0; $i <= $count; $i++)
{
echo "<tr>";
echo "<td>".$_SESSION['tariff_name'][$i]."</td>";
echo "<td>".$_SESSION['tariff_net'][$i]."</td>";
echo "<td>".$_SESSION['tariff_inclusive'][$i]."</td>";
echo "<td>".$_SESSION['tariff_length'][$i]."</td>";
echo "<td>".$_SESSION['tariff_data'][$i]."</td>";
echo "</tr>";
}
}
Paste bin of php page - http://pastebin.com/petkrEck
Any ideas, why my If statement is not catching the event when the user presses "Add another tariff" button the first time it is pressed, but then detects it afterwards?
Thanks for your time
Merry Christmas!

The problem is your code flow. In simplified pseudo-code, you're doing this:
if (session is not initialized) {
set = true
count = 0;
} else {
add posted data to session
}
On the first 'add item' call, the session is not set up, so you set up the session. AND THEN IGNORE THE POSTED DATA.
The code flow should be:
if (session is not initialized) {
set = true;
count = 0;
}
if (posting data) {
add data to session
}

Related

Storing a $_GET to $_SESSION when form is on every page Contact Form 7

I have a form on every page that is a quick navigation. Based on the value of the drop-downs it will redirect to a specific page. The URL after using it will look like /page?first=abc&second=def&third=ghi. If you leave the page and go to pageB the url will just say /pageB. I'm trying to create a SESSION for second if it's set and when it's no longer set (navigating to a different page not using the quicknav) still store the value when it was set. Here is what I have so far...
function storeVariable {
global $saved_second
$store_second = $_GET['second'];
$saved_second ='';
if (isset($store_second)) {
$_SESSION['second'] = $_GET['second'];
$sessionsecond = $_SESSION['second'];
$saved_second = $sessionsecond;
}
return $save_second
}
In the header I have
global $saved_second;
echo $saved_second;
The above code is fine for the initial page the quick navigation goes to. It shows the value of $saved_second in the header. I'm not sure how I would say
if (isset($saved_second) && (!isset($stored_second) {
USE SESSION THAT WAS CREATED WHEN $stored_second WAS SET
I thought something like...
if ($store_second != $sessionsecond){
but that doesn't work either because the session was created in an IF statement.
Then I tried...
IF (!isset($saved_second)) {
IF (isset($_GET['second'])) {
$_SESSION['second'] = $_GET['second'];
$saved_second = $_SESSION['second'];
}}
Any suggestions?

Incrementing the value of the post by every repeated form submission

I have a form sender which is posting a value of 6 to another form receiver. What I'm trying to achieve is store the posted value from sender into a variable in the receiverthen increment the variable it every time the sender posts. Then print the updated variable
This is what I have tried to do
$val= $_POST['val'];
$limit = 6 + $val;
echo $limit;
Im getting the result as 12. But what I want is
After first post result = 12
After second post result = 18
On and on...
NB:$_POST['val'] = 6;
session_start();
$limit = 6;
if(!isset($_SESSION['lastLimit'])) {
$_SESSION['lastLimit'] = 0;
}
if(!empty($_POST)) {
$_SESSION['lastLimit'] = $_SESSION['lastLimit'] + $limit;
$postedValue = $_POST['val'] + $_SESSION['lastLimit'];
echo $postedValue;
}
Because the web is stateless i.e. scripts do not remember anything that happened the last time a page/form was executed the receiver script does not remember anything from the last time it was run.
But dont panic, there is a way. Its called a SESSION and you can store data in the session which will then be available the next time this user connects to your site. In PHP you use it like this. The session is linked to this specific connection to a specific user.
receiver.php
<?php
// must be run at top of script, before any output is sent to the new form
session_start();
// did the form get posted and is the variable present
// or replace POST with GET if you are using an anchor to run the script
if ( $_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['val']) {
if ( isset($_SESSION['limit'] ){
// increment the limit
$_SESSION['limit'] += (int)$_POST['val'];
} else {
// initialize the limit
$_SESSION['limit'] = (int)$_POST['val'];
}
echo 'Current value of limit is = ' $_SESSION['limit'];
} else {
// something is not right
// direct this user to some basic page like the homepage or a login
header('Location: index.php');
}
You need an intermediate layer to store the value.
Available options:
1) Global static value
2) session
3) file
4) database
I would recommend global value or session, as they data you want to store isn't that huge and would meet the requirements easily.
I would not write the syntax to store it in session as a number of people have already mentioned it. I just wanted to clarify the problem scenario and possible solutions.
You can store $limti into global varibale .
global $val;
$val += $_POST['val'];
$limit = 6 + $val;
echo $limit;

php form POST- variable can't increment

I'd like to increment a variable on clicking a submit button with name="ticker".
$speed = 0;
if ( isset($_POST['ticker'])){
echo $speed++;
}
What I want is to be able to repeatedly click the button and see 1 added to total each time clicked. It seems to work once and then stays at "1". Why?
session_start();
if(!isset($_SESSION['speed'])) $_SESSION['speed'] = 0;
if(isset($_POST['ticker'])){ /* If there is already a value set */
$_SESSION['speed']++; /* Increment by 1 */
}
If you want to increment variable after clicking submit, you should store this value to $_SESSION['speed'] and after that increment it. In this case you set speed on value 0 and each time you click on the submit is incremented by one.

Using For loop to get values of multiple elements in PHP

The title is so general mainly because I don't know what should be the appropriate title for it. Let me just explain the situation:
Say that I have two textboxes named LastName0 and FirstName0 and a button called addMore. When I click addMore, another two textboxes will be created through JavaScript. These textboxes will be named LastName1 and FirstName1. When I click the addMore button again, another two textboxes button will be created and named LastName2 and FirstName2 respectively. This will go on as long as the addMore button is clicked. Also, a button named deleteThis will be created alongside the textboxes. This simply deletes the created textboxes when clicked.
I also initialized a variable called counter. Every time the addMore button is clicked, the counter goes up by 1, and whenever the deleteThis button is clicked, the counter decreases by 1. The value of the counter is stored in a hidden input type.
When the user submits the form, I get the value of the counter and create a For loop to get all the values of the textboxes in the form. Here is the sample code:
//Suppose that the user decides to add 2 more textboxes. Now we have the following:
// LastName0 FirstName0
// LastName1 FirstName1
// LastName2 FirstName2
$ctr = $_POST['counter']; //the counter == 3
for ($x = 0; $x < $ctr; $ctr++)
{
$lastname = $_POST["LastName$x"];
$firstname = $_POST["FirstName$x"];
//This will get the values of LastName0,1,2 and FirstName0,1,2
//code to save to database…
}
On the code above, if the value of counter is equal to 3, then the values of textboxes LastName0,1,2 and FirstName0,1,2 will be saved. Now here is the problem: If the user decided to delete LastName1 and FirstName1, the For loop will not be able to iterate properly:
$ctr = $_POST['counter']; //the counter == 2
for ($x = 0; $x < $ctr; $ctr++)
{
//Only LastName0 and FirstName0 will be saved.
$lastname = $_POST["LastName$x"];
$firstname = $_POST["FirstName$x"];
//code to save to database…
}
Someone told me to use the "push and pop" concept to solve this problem, but I am not really sure on how to apply it here. So if anyone can tell me how to apply it, it'll be grand.
Add your input text boxes with name as array ie, <input type="text" name="FirstName[]" />
In php you can fetch them as a array. ie,
foreach($_POST["FirstName"] as $k=>$val){
echo $val; // give you first name
echo $_POST["LastName"][$k]; // will give you last ame
}
In this case even if one set of field is removed in HTML will not affect the php code.
One solution would be to use the isset function like this:
$ctr = $_POST['counter'];
for ($x = 0; $x < $ctr; $ctr++)
{
isset($_POST["LastName$x"])?$lastname = $_POST["LastName$x"]:;
isset($_POST["FirstName$x"])?$firstname = $_POST["FirstName$x"]:;
}
If it is possible, instead of using LastNameN and FirstNameN names try using LastName[N] and FirstName[N], this way the result is an array and you can iterate through it with a foreach, meaning you will not need the counter and the index of the value will not be important:
foreach ($_POST["LastName"] as $i=>$lastname) {
if (!isset($_POST["FirstName"][$i])) {
// This should only happen if someone messes with the client side before posting
throw new Exception("Last name input does not have a related First name input");
}
$firstname = $_POST["FirstName"][$i];
}
If not, then you may have to use your $counter in a different way
$current = 0;
while ($counter) { // Stop only when i found all
if (isset($_POST["LastName$current"]) {
$counter--; // Found one
$lastname = $_POST["LastName$current"];
$firstname = $_POST["FirstName$current"];
}
$current++;
}
A better way to solve this would be to use arrays for Firstname and Lastname. Instead of calling them Lastname0 and Firstname0, then Lastname1 and Firstname1, call them all Lastname[] and Firstname[]. Give them ID's of Lastname0 and Firstname0 and so on for the delete function, but keep the names as arrays.
When the form is submitted use the following:
foreach($_POST['Lastname'] as $i => $lastname) {
$firstname = $_POST['Firstname'][$i]
//... code to save into the database here
}
Be warned though that in IE if you have an empty field it will not be submitted, so if Lastname0 has a value, but Firstname0 does not, then $_POST['Firstname'][0] will in fact contain the value of Firstname1 (assuming it has a value in it). To get around this you can use javascript to check if a field is empty when submitting the form, and if so put the word EMPTY in it.
Do not use counter if not required
A much easier way is to add array name when admore clicked.
Give a name like first_name[] in textbox
if you create form like that you can use foreach through $_POST['first_name']
try var_dump($_POST) in you php code to see how things goes on.
Inside your for loop, maybe you could try...
if ((isset($_POST["LastName$x"])) && (isset($_POST["FirstName$x"]))){
$lastname = $_POST["LastName$x"];
$firstname = $_POST["FirstName$x"];
//code to save to database…
}
This will check if the variables exists before you try to do anything with them.

checkbox's stay checked after pagination in php

Hello i want any checkbox i am gonna check, to stay checked after pagination.
here is the code:
foreach($test as $string){
$queryForArray = "SELECT p_fname,p_id FROM personnel WHERE p_id = " .$string["p_id"]. " ;" ;
$resultForArray = mysql_query($queryForArray, $con);
$rowfForArray = mysql_fetch_array($resultForArray);
?>
<td id="<?php echo $rowfForArray["p_id"]?>" onclick="setStyles(this.id)" ><?php echo $rowfForArray["p_fname"]?></td>
<td><input id="<?php echo $rowfForArray["p_id"]?>" class="remember_cb" type="checkbox" name="how_hear[]" value="<?php echo $rowfForArray["p_fname"]?>"
<?php foreach($_POST['how_hear'] as $_SESSION){echo (( $rowfForArray["p_fname"] == $_SESSION) ? ('checked="checked"') : ('')); } ?>/></td>
</tr>
<tr>
I am geting the data from a search result i have in the same page , and then i have each result with a checkbox , so that i can check the "persons" i need for $_Session use.
The only think i want is the checkbox's to stay checked after pagination and before i submit the form!(if needed i can post the pagination code, but he is 100% correct)
In the checkbox tag use the ternary operation, without that foreach inside him:
<input [...] value="<?php echo $rowfForArray["p_fname"]?>" <?php $rowfForArray["valueToCompareIfTrue"] ? "checked='checked'" : ''; ?> />
because the input already is inside of 'for' loop, then each time of the loop will create a new checkbox wich will verify if need to being check or not.
I hope I have helped you.
A few ways to tackle this:
(Straight up PHP): Each page needs to be a seperate form then, and your "next" button/link needs to submit the form everytime they click next. The submit data should then get pushed to your $_SESSION var. The data can then be extracted and used to repopulate the form if they navigate backwards as well. Just takes some clever usage of setting the URL with the proper $_GET variables for the form.
(HTML5): This will rely more on JavaScript, but basically you get rid of pagination and then just break the entire data set into div chunks which you can hide/reveal with JavaScript+CSS or use a library like JQuery.
(AJAX): Add event listeners to the checkboxes so that when a button is checked an asynchronous call is made back to a PHP script and the $_SESSION variable is updated accordingly. Again, this one depends on how comfortable you are with JavaScript.
Just keep in mind that PHP = ServerSide & JavaScript = ClientSide. While you can hack some PHP together to handle "clientside" stuff, its usually ugly and convoluted...
I did it without touching the database...
The checkbox fields are a php collection "cbgroup[]".
I then made a hidden text box with all the values which equal the primary keys of the selectable items mirroring the checkboxes. This way, I can iterate through the fake checkboxes on the current page and uncheck the checkboxes by ID that exist on the current page only. If the user does a search of items and the table changes, the selectable items remain! (until they destroy the session)
I POST the pagination instead of GET.
After the user selects their items, the page is POSTED and I read in the hidden text field for all the checkbox IDs that exist on that current page. Because PhP only tells you which ones are checked from the actual checkboxes, I clear only the ones from the session array that exist on the POSTED page from this text box value. So, if the user selected items ID 2, 4, 5 previously, but the current page has IDs 7,19, and 22, only 7, 19, and 22 are cleared from the SESSION array.
I then repopulate the array with any previously checked items 7, 19, or 22 (if checked) and append it to the SESSION array along with 2, 4, and 5 (if checked)
After they page through all the items and made their final selection, I then post their final selections to the database. This way, they can venture off to other pages, perhaps even adding an item to the dB, return to the item selection page and all their selections are still intact! Without writing to the database in some temp table every page iteration!
First, go through all the checkboxes and clear the array of these values
This will only clear the checkboxes from the current page, not any previously checked items from any other page.
if (array_key_exists('currentids', $_POST)) {
$currentids = $_POST['currentids'];
if (isset($_SESSION['materials']) ) {
if ($_SESSION['materials'] != "") {
$text = $_SESSION['materials'];
$delimiter=',';
$itemList = explode($delimiter, $text);
$removeItems = explode($delimiter, $currentids);
foreach ($removeItems as $key => $del_val) {
//echo "<br>del_val: ".$del_val." - key: ".$key."<br>";
// Rip through all possibilities of Item IDs from the current page
if(($key = array_search($del_val, $itemList)) !== false) {
unset($itemList[$key]);
//echo "<br>removed ".$del_val;
}
// If you know you only have one line to remove, you can decomment the next line, to stop looping
//break;
}
// Leaves the previous paged screen's selections intact
$newSessionItems = implode(",", $itemList);
$_SESSION['materials'] = $newSessionItems;
}
}
}
Now that we have the previous screens' checked values and have cleared the current checkboxes from the SESSION array, let's now write in what the user selected, because they could have UNselected something, or all.
Check which checkboxes were checked
if (array_key_exists('cbgroup', $_POST)) {
if(sizeof($_POST['cbgroup'])) {
$materials = $_POST['cbgroup'];
$N = count($materials);
for($i=0; $i < $N; $i++)
{
$sessionval = ",".$materials[$i];
$_SESSION['materials'] = $_SESSION['materials'].$sessionval;
}
} //end size of
} // key exists
Now we have all the items that could possibly be checked, but there may be duplicates because the user may have paged back and forth
This reads the entire collection of IDs and removes duplicates, if there are any.
if (isset($_SESSION['materials']) ) {
if ($_SESSION['materials'] != "") {
$text = $_SESSION['materials'];
$delimiter=',';
$itemList = explode($delimiter, $text);
$filtered = array();
foreach ($itemList as $key => $value){
if(in_array($value, $filtered)){
continue;
}
array_push($filtered, $value);
}
$uniqueitemschecked = count($filtered);
$_SESSION['materials'] = null;
for($i=0; $i < $uniqueitemschecked; $i++) {
$_SESSION['materials'] = $_SESSION['materials'].",".$filtered[$i];
}
}
}
$_SESSION['materials'] is a collection of all the checkboxes that the user selected (on every paged screen) and contains the primary_key values from the database table. Now all you need to do is rip through the SESSION collection and read\write to the materials table (or whatever) and select/update by primary_key
Typical form...
<form name="materials_form" method="post" action="thispage.php">
Need this somewhere: tracks the current page, and so when you post, it goes to the right page back or forth
<input id="_page" name="page" value="<?php echo $page ?> ">
if ($page < $counter - 1)
$pagination.= " next »";
else
$pagination.= "<span class=\"disabled\"> next »</span>";
$pagination.= "</div>\n";
Read from your database and populate your table
When you build the form, use something like this to apply the "checked" value of it equals one in the SESSION array
echo "<input type='checkbox' name='cbgroup[]' value='$row[0]'";
if (isset($filtered)) {
$uniqueitemschecked = count($filtered);
for($i=0; $i < $uniqueitemschecked; $i++) {
if ($row[0] == $filtered[$i]) {
echo " checked ";
}
}
}
While you're building the HTML table in the WHILE loop... use this. It will append all the select IDs to a comma separated text value after the loop
...
$allcheckboxids = "";
while ($row = $result->fetch_row()) {
$allcheckboxids = $allcheckboxids.$row[0].",";
...
}
After the loop, write out the hidden text field
echo "<input type='hidden' name='currentids' value='$allcheckboxids'>";

Categories