Hi Guys

I need some help. I am trying to modify a website which is based on template engines and I am not sure how to do the following.

I have added a drop down box to the header.tmp and the form action posts the user selection (user_loc) to another form (loc.php). Loc.php updates the database with the user selection and then queries the same database to 'look up' the current value of user_loc so that it can be inserted as the default selection in the listbox for the current session and all subsequent sessions. So in effect, whenever the user makes a selection it is written to the database and that selection becomes the users default setting forever unless he changes it.

The problem is that I do not know how to get the looked up value of user_loc back into the header.tmp so it can be set as that users default selection. If I tell loc.php to process the header.tmp it does not have all the required variables because it was only designed to parse the user_loc variable.

Any help would be appreciated. I can paste my code on request.

Cheers

EJ

EJ, I take it you know how to cause a particular option in a < SELECT > menu to be selected?

HTML
< option value="xxx" selected >

XHTML
< option value="xxx" selected="selected" >MyText< /option >

You need to build your select menu dynamically, inserting selected into the appropriate option. Do this by whatever means available within the language/templating system you are using (typically a combination of string handling and variable/array setting).

Airshow

Thanks Airshow it may be easier if I include my code

For the drop down box in header.tmp :

<form action="loc.php" method="post" >
<input type="hidden" name="option" value="loc_search">
<td><select name="user_loc" onchange="this.form.submit();">

<option value="A" <? echo ($loc_details['user_loc']=='A') ? 'selected' : ''; ?>><?=MSG_USA;?></option>
	  			
<option value="B" <? echo ($loc_details['user_loc']=='B') ? 'selected' : ''; ?>><?=MSG_BERMUDA;?></option>
				
<option value="C" <? echo ($loc_details['user_loc']=='C') ? 'selected' : ''; ?>><?=MSG_CANADA;?></option>

</select></td>
 
</form>

For loc.php :

$selected_loc= $_POST['user_loc'];

$update_sql_loc= $db->query("UPDATE " . DB_PREFIX . "users SET user_loc ='" . $selected_loc  . "'WHERE user_id='" . $session->value('user_id') . "'");

$loc_details = $db->get_sql_row("SELECT * FROM " . DB_PREFIX . "users WHERE user_id=" . $session->value('user_id'));

$template->set('user_loc', $loc_details);

$refresh_link = 'index.php';

$template_output .= '<script>window.setTimeout(\'changeurl();\',300); function changeurl(){window.location=\'' . $refresh_link . '\'}</script>';

#$template_output .= $template->process('header.tpl.php');

echo $template_output;

You will note that I have commented out the penultimate line because its causing me problems. I do not really want to process the whole header because loc.php does not have all the required variables. But I need the dropdown to remember the users selected location (without resorting to cookies).

Cheers EJ

I'm going to describe the changes you need to do (in pseudo-code) rather than write it for you. That way you will learn more.

There are quite a few issues here, mostly functional but also concerning security and error handling.

1.)

$selected_loc = $_POST['user_loc'];

To make life easier lower down, suggest changing this line to:

$user_loc = (isset($_POST['user_loc'])) ? htmlspecialchars($_POST['user_loc']) : null;[/ICODE]

Note protection against malicious code injection by use of htmlspecialchars(), and handling the case where $_POST['user_loc'] is not set (it is tested for null below).
You might also like to do some range checking here. You are expecting a single uppercase character, so make sure it is.

2.)

$update_sql_loc = $db->query(.....);

You are currently doing this unconditionally, therfore when the page is called with $_POST['user_loc'] not set (ie. when an update has not been demanded), then the database will be updated with an invalid value.
Wrap in if($user_loc != null){ }

Also, you need to handle the case where the db update fails, eg.

if(!$update_sql_loc = $db->query(.....)){ die(.....); }

3.)

$loc_details = $db->......

You only need to do this if the db has not just been updated (line above), otherwise you already know the value you are looking up ie. $selected_loc == users.user_loc if the db has just been updated.
Wrap in else{ }

Within this else block:-
After the db query, set $user_loc to $user_details['user_loc']. Hence, $user_loc is either the new value just written to the db or the previous value retrieved from the db. Either way, it's the value yo want.
Also, would $user_details be a better variable name than $loc_detals? After all, it's a whole array of user data, not just the loc.
Again, you need to handle the case where the db query fails, eg.

if(!$user_details = $db->......){ die(.....); }

4.)

$template->set('user_loc', $loc_details);

I confess I don't know this particular templating system but would guess that this line is incompatible with the code in the template file. Suggest:

$template->set('user_loc', $user_loc);

Then in the template:

<option value="A" <? echo ($user_loc=='A') ? 'selected' : ''; ?>><?=MSG_USA;?></option>

and similar for the other options.

I'm afraid I can't test any of this here as I don't have your template class. Maybe you could give me a clue?

Good luck

Airshow

Hello again Airshow and many thanks for your suggestions.

My amendments to loc.php are set out below but I am getting the following error message (repeated several times) : No such file or directory, failed to open stream at line 47 in class_template when I select an option from the dropdown and the dropdown is not remembering the user selection.

Loc.php code :

if (isset($_POST['user_loc'])) 
{
	$user_loc = (isset($_POST['user_loc'])) ? htmlspecialchars($_POST['user_loc']) : null; 

		if($user_loc != null)
	{ 
		$update_sql_loc= $db->query("UPDATE " . DB_PREFIX . "users SET user_loc ='" . $user_loc  . "'WHERE user_id='" . $session->value('user_id') . "'") or die(mysql_error());
	} 

}
else
{

	$user_loc = $db->get_sql_row("SELECT user_loc FROM " . DB_PREFIX . "users WHERE user_id=" . $session->value('user_id')) or die(mysql_error());
	
}

$template->set('user_loc', $user_loc);

$template_output .= $template->process('header.tpl.php');

$refresh_link = 'index.php';

$template_output .= '<script>window.setTimeout(\'changeurl();\',300); function changeurl(){window.location=\'' . $refresh_link . '\'}</script>';

echo $template_output;

The class_template file code is as follows and the template is based on the code of Brian E. Lozier. Line 47 is highlighted with a code comment.

class template

{

	## constructor, set the home directory for the templates
	function template($path)
	{
		$this->path = $path;
	}

	## change template path if needed
	function change_path($path)
	{
		$this->path = $path;
	}

	## assign variables that will be used in the template used.
	function set($name, $value)
	{
		$this->vars[$name] = $value;
	}

	## process the template file
	function process($file)
	{
		@extract($this->vars);
		ob_start();
		include($this->path . $file); # This is line 47
		$contents = ob_get_contents();
		ob_end_clean();
		return $contents;
	}

Any suggestions would be most welcome. On the subject of which, is there a problem trying to process the whole of a header.tmp with a php page (loc.php) when loc.php was only designed to work with one section of it (namely, my drop down)?

And I am confused by what code collects the user_loc variable from the database when the user starts a session? The drop down is coded to work 'onchange' so how does the page know which variable the user selected as his default in a previous session if the dropdown is not amended i.e. so there is no 'onchange' event to post to loc.php?

Many thanks in advance

EJ

EJ,

First, let's get the overall scenario right.

As I understand it, your script needs to work on many different pages, so it will eventually be moved to a separate .php file and brought into each page as necessary using include() or require().

(By making the script an include, you will avoid the need for a dedicated .php page to do the updating, and also avoid the necessity to do that double-shuffle with window.setTimeout(). By making your script an include it becomes available for inclusion on as many pages as necessary and will work on all of them.)

However, for testing it is easier to have the code directly on a test page; lets call it test.php .

There's an implicit assumption in the way your original php is written, that the same script should handle update and retrieval of user_loc (to/from the db), and the composition of a corresponding < select > menu which displays to each user their current user_loc setting and also allows them to change it.

Consequently, your script must either update OR retrieve user_loc, AND must always build the menu.

The script is instructed whether to update or retrieve by the presence/absence of $_POST['user_loc' ] . Hence the if(){}else{} structure at the top of the script.

OK.

The code that retrieves the required value from the database is your line:

$user_loc = $db->get_sql_row("SELECT ........

However, as currently written, it is probably not correct. On the assumption that $db->get_sql_row returns an array (I use a db class with a different set of commands), try replacing with the following two lines:

$user_details = $db->get_sql_row("SELECT ....... (etc.)
$user_loc = $user_details['user_loc'];

Now for the template. I've looked at a Brian Lozier article on templates but think the class he describes is different from the one you pasted above. I cannot therefore really check your $template code but from the error message you report, I must assume that either $template in instantiated incorrectly (wrong path passed to the constructor) and/or the file 'header.tpl.php' does not exist. Check both.

What I think you need now is a strategy for testing the various elements of your code without others interfering, for example:

  • Ensure that the form method (in the template) points back to your test page (test.php).
  • Suppress all the $_POST and database stuff in your script and get your template working. It is central. Hard code $user_loc and see if it is correctly reflected in the rendered template.
  • Reintroduce the $_POST code and ensure that 'user_loc' is being passed in correctly and that $user_loc is set accordingly. Use 'View Source' in your browser to inspect the generated HTML.
  • Finally reintroduce the $db code and ensure that that (a) the selected value of user_loc is being saved and (b) that the stored value gets correctly retrieved. Inspect the database directly using eg. phpMyAdmin to see the value that is actually stored and to change it manually if necessary.

This is a pretty typical development strategy for a web page with client side scripting. Most web developers will have done similar many times over.

Good luck

Airshow

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.