When backward is forward

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
PixelMaster
Forum Newbie
Posts: 11
Joined: Sat Aug 16, 2003 11:48 am

When backward is forward

Post by PixelMaster »

Ok ... I have a bit of code here which mysteriously enough, works. Not that I'm accustomed to writing code that doesn't ... this is just a bit counterintuitive. Here it is:

Code: Select all

<?php
$revPOST = array_flip($_POST);
		foreach ($revPOST as $key=>$value) {
			$this->$value = $_POST[$value];
		}
?>
It is from a class, and is called with the constructor, after data validation. It works like extract(), excepts it creates class properties instead of locally scoped variables (ie., $this->myVar instead of $myVar.)

I know that it works, but I'm missing a piece or two from the puzzle of why it works. I have a hunch that it has to do with references and the way class variables work, but I'm unsure of that. Anyone have any clues?
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

The principle is (sort of) OK, but the code isn't quite right.

Code: Select all

<?php

// no array flipping needed
foreach($_POST as $key=>$value)
{
    $this->$key = $value;
}

?>
In the same way that you can declare a class property with $this->var = 'value'; you can declare a whole bunch in a loop. Referencing isn't involved.

It can seem like a neat way to do it but there are issues.

It's possibly better to make the effort to name the vars explicitly so you can see at a glance what properties are being declared when you come back to read the code at a later date and have forgotten what was in the form.

Also, auto-extracting user input can be extremely dangerous. A forged form could add any var with any value to the $_POST array and an extract() or a foreach() loop like the above instantly declares them all in your script, possibly overwriting other vars with the same name and in the same scope as the extract/foreach code or setting values for undefined vars.

Inside a function, often the first thing you do is get the POST values and, if so, there isn't anything else in the fn scope to overwrite at that point* (if NOT you're in trouble). Later on, your script would itself overwrite any poisoned POST vars. Assuming you don't have any undefined vars (E_ALL.. ) you'd be safe.

* apart from the fn args, if there are any

However, inside a class, properties have a kind of "global class scope" and so auto-extracting user input as properties carries a greater risk. It's likely that a bunch of properties have already been declared and are sitting around, just waiting to be poisoned.

In saying that, I do sometimes do it myself. For example, it's convenient when you're developing and haven't yet finalised all the form elements.

Also, you mentioned that you have checked the POST array beforehand. If you have some kind of "alien key" check as part of that process you would pick up an attempt at variable substitution by adding new keys to the POST array. That lets you be sure you're extracting just the $keys you expect - although of course you still can't assume their values are good.[/i]
Last edited by McGruff on Wed Aug 10, 2005 8:21 pm, edited 1 time in total.
User avatar
PixelMaster
Forum Newbie
Posts: 11
Joined: Sat Aug 16, 2003 11:48 am

Post by PixelMaster »

Actually, the code works exactly the way it is ... my first attempt was, in fact, more or less the same as your suggestion. But it doesn't work: you end up with variables like $this->steadyguy with a value of username. Trust me, I spent several days trying all the possible configurations. This is the only one that works the way I expect/want it to. YOU MUST flip the array, or it won't work ...

As for the security issues, I am plenty aware of them. And though you are correct, they are not the topic of this thread. What I really want to know is why the code I supplied above works, while the code that is intuitive (ie., the solution you supplied) gives highly unexpected results.
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

PixelMaster wrote:Actually, the code works exactly the way it is ... my first attempt was, in fact, more or less the same as your suggestion. But it doesn't work: you end up with variables like $this->steadyguy with a value of username
You set POST keys as $revPOST values, and then used these rather than the original POST keys. Why?

It's kind of academic cos it's not really a good thing to do anyway IMHO.

Sorry if I went into lecture mode but you never can tell what level of knowledge posters have; also other people will be reading this. Auto-extracting user input is quite common but not everyone may realise the implications.
User avatar
PixelMaster
Forum Newbie
Posts: 11
Joined: Sat Aug 16, 2003 11:48 am

Post by PixelMaster »

McGruff wrote: You set POST keys as $revPOST values, and then used these rather than the original POST keys. Why?
I know ... it is completely counterintuitive. But I couldn't assign the appropriate value (in my example case, 'steadyguy') to $this->username any other way.

Any ideas why it works this way?
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Really the two bits of code are the same except that, in your example, the $_POST keys take a detour via $revPOST values. Maybe you need the flipped array for some other purpose in the script but, purely to extract all the post array items as properties, the snippet which I posted should work. I can't think why that wouldn't work for you.

The principle in either example is the same: ie using variable variable names to declare vars (or rather class properties in this case). http://uk2.php.net/variables.variable

On a side note, this works with functions as well, eg:

$var = $function_name();

.. which can be handy to save a bunch of if/elses or switch/cases, amongst other things.
User avatar
Heavy
Forum Contributor
Posts: 478
Joined: Sun Sep 22, 2002 7:36 am
Location: Viksjöfors, Hälsingland, Sweden
Contact:

Re: When backward is forward

Post by Heavy »

Maybe you have collisions in the values of $_POST that are solved by this very strange piece of code.
It should be a quite simple task to debug this using print_r():

Code: Select all

<?php
	$revPOST = array_flip($_POST);
	foreach ($revPOST as $key=>$value) {
		$this->$value = $_POST[$value];
	}
	print_r($_POST);
	print_r($revPOST);
	print_r($this);
?>
and

Code: Select all

<?php
	foreach($_POST as $key=>$value)
	{
	    $this->$key = $value;
	} 
	print_r($_POST);
	print_r($this);
?>
Compare the results and take appropriate action :wink:
User avatar
Heavy
Forum Contributor
Posts: 478
Joined: Sun Sep 22, 2002 7:36 am
Location: Viksjöfors, Hälsingland, Sweden
Contact:

Post by Heavy »

Will this help?

Code: Select all

<?php
   $arrPost = array_unique($_POST);
   foreach($arrPost as $key=>$value)
   {
       $this->$key = $value;
   }
   print_r($_POST);
   print_r($this);
?>
Post Reply