Is there any way

To make sure that a function you are calling “blind” is not accepting your parameters by reference?

I’m making a module loading system where all the modules have a common function that I want to pass my settings variable to (which is private to the main object) – but I don’t want to risk an errant module writer (read hacker) going and using & to change any of it’s values. (much less in the skins).

Is there any way to check the ‘structure’ or parameters of a function in PHP?

(what I wouldn’t give for strict typecasting and prototyping about now).

My google-fu and knowledge of php.net is failing me.

I wonder if [fphp]debug_zval_dump[/fphp] could be handy too.

So you want to make sure myFunction is passed as myFunction() vs myFunction(‘abc’)?

PHP: Spotting References - Manual or [url=http://www.php.net/manual/en/reflectionparameter.ispassedbyreference.php]ReflectionParameter::isPassedByReference ?

How about cloning the objects before passing them along?

Actually, you pointed me the right direction, as this:
PHP: ReflectionFunctionAbstract::getParameters - Manual

Is what I’m after… though I’m not sure I want to use an undocumented function call.

to clarify, let’s say I’m inside an object


class myThing {
private
  $settings=array();

somewhere in my code a ‘module’ of functions is loaded via require once… let’s say…


function theme_header($settings) {

I have no way to predict what code will actually be in theme_header so I want to make sure that nobody can do:


function theme_header(&$settings)

in their code.

Basically, I’d like to pass $settings as read-only, or failing that run a check on the function before I call it to see what it’s parameters are…

In general, anything passed from the object should NOT be passed by reference, and the functions should fit a certain ‘template’ of definition.

Which is another thing I’d love to have in PHP – forward declaration… You can kind-of fake it using objects, but public/private/protected just doesn’t cut it.

ahundiak’s idea of passing a copy has some merit, but I’m going to be passing two really big arrays, so making extra copies in memory when not passing it by reference will already make an extra copy… not exactly ideal.

THOUGH… hah, I could make a copy, then pass the copy by reference – that’s the same number of copies in memory as not passing by reference.

Sounds like you should be using an object that only allows the reading via your favorite things getters. In this case probably a single getter that accepts the name of a setting and returns the value.

With the amount of data being passed… and the need to dynamically handle it… uhm, no.

Though “only allows reading” is something of a… impossibility with PHP. Shortcoming in most programming languages IMHO; Be nice to have a programming language that had a true permissions system per variable much akin to how a *nix filesystem works. Would be more overhead, but even just a fourth state in PHP like “publicReadOnly” – behaves like private for writes, public for reads.

Given this is running php user functions inside a ‘secure’ system, checking the parameters of the user functions seems the best approach – now to see if I can make sense out of reflections as I’ve not really used them before.

Turns out I was close – getParams only lists their names. The only thing that actually shows you what the function has for parameters INCLUDING & is the ::__toString reflection method…

So I wrote a parser to dump it to an array.


function getFunctionParameters($functionName) {
	$data=new ReflectionFunction($functionName);
	$data=explode("\
",strstr($data->__toString(),'- Parameters ['));
	if (
		($paramCount=substr(
			$data[0],
			14,
			strpos($data[0],']',14)-14
		))==0
	) {
		return false;
	} else {
		$result=array();
		$index=0;
		while ($index<$paramCount) {
			$index++;
			$offset=strpos($data[$index],'[')+1;
			$result[]=trim(substr(
				$data[$index],
				$offset,
				strpos($data[$index],']',$offset)-$offset
			));
		}
		return $result;
	}
}

Which seems to do what I wanted. I could probably use a regex (or multiple regex) for this, but I’m not sure it’s worth the overhead.

Seems a little verbose.


<?php
function isFunctionParameterPassedByReference($function, $parameter){
  $f = new ReflectionFunction($function);
  foreach($f->getParameters() as $p){
    if($parameter === $p->getName()){
      return $p->isPassedByReference();
    }
  }
  throw new InvalidArgumentException('$parameter invalid');
}


function foo($a, &$b){  }

var_dump(
  isFunctionParameterPassedByReference('foo', 'a')
);

var_dump(
  isFunctionParameterPassedByReference('foo', 'b')
);

/*
  bool(false)
  bool(true)
*/

I think you are trying to be way to clever. Just pass an object without any setters.


class ReadOnlySettings
{
  protected $settings = array();
  public __construct ( array $settings ) {}
  public __get ( $var )
  {
    if ( isset( $this->settings[ $var ] ) )
      return $this->settings[ $var ];
    throw new exception( "Invalid option" );
  }
}

$c = new ReadOnlySettings( array( 'cat' => 'mew' ) );
echo $c->cat;

But I think you are being paranoid for some unknown reason. Why would you run untrusted code?
The reason there are no permissions on variables because it does not make sense. That level of abstraction is really not required.

FWIW, I’d pass an object too.

What if the function names its parameters differently? E.g. function foo($cake, &$pie)

How would that help at all against the problem of a function modifying that object?

How do you stop said code from changing the source files with file_put_contents?

Well, the OP was only really looking to see if any were passed by reference, so I just wouldn’t check a specific parameter.

Unless of course, you’re hinting at something else? :-/

isPassedByReference doesn’t seem to actually work here… No, wait… the foreach is failing… gah.

In any case, I’d rather turn an array – but you’ve got me moving forwards at least… This is proving why I hate “reflections” and many of the object based parts… It’s all spaghetti in terms of even figuring out what properties are valid or even exist.

Something that’s heresy to object fans – in many way objects when tons of inheritance on the board are more twisted than old-school direct jumps. Not bad enough reflections aren’t even fully documented with most of the properties being “This function is currently not documented; only its argument list is available.” (probably meaning subject to change without notice too) – the this inherits from this inherits from this and returns this; bad enough to make you wish for the days of line numbered basic.

Alright, I’m gonna play with this. Still learning reflections – seems needlessly complicated for stuff that should be a few simple calls; and wasteful of memory since it’s all these massive copies of stuff that already exists.

But of course, modern code acts like RAM grows on trees.

Well, there is that option but I was thinking more along the lines of the passed-in settings variable being changed at runtime very easily. Your class, as magic as it is, doesn’t help with deathshadow60’s problem at all.

That was my point, your snippet checked whether a parameter is passed by reference by specifying the parameter name only. I was just saying that that’s a silly idea and I think deathshadow60 could see that too based on his earlier code.

It’s definately an option – it just feels silly to waste the overhead of an object on this. Reeks of the “let’s throw objects at everything” nonsense – though in this case it at least has a reason, overcoming shortfalls in how PHP works. The mere concept of adding extra “__get” or “__set” functions just seems so… wasteful… Though certainly no more wasteful than anything else mentioned so far in this thread.

Though no… not an option, as there will be functions that SHOULD be able to modify it and/or add to it as well… so locking it out completely doesn’t fly either. There is a point in the code at which stuff stops being added to the array – but that’s well after where I start wanting some functions not to be able to access it since I’m doing PGO (parse-generate-output… a play on MVC that cuts out all the oddball wasteful code overhead that trying to implement true MVC on PHP brings with it. Parser figures out what the user-agent wants to do, the generator does it, the output sends it…)

If there was a point at which I could say “ok, from this point on no changes” __get is very attractive, it’s just not an option here; well… I could use that on output via a re-assignment… that might simplify theme coding.

The same reason turdpress does? Custom Skins, custom mods, all of which make 80%+ of wordpress vulnerabilities be in what people add to the code. Hence that nice little pwnie they won back in '08? (still no excuse for all the gaping massive holes elsewhere in it though… un/pw in DEFINE? really? REALLY? REALLY?!?)

A lot of this paranoia as you call it comes from exploits I’ve had crop up in software I’ve been using on servers the past decade… and observations of software I’ve had to clean up after for others… Wordpress, phpBB, SMF – it’s bad enough when there’s a hole to get in the door, but to take NO precautions in terms of isolating bits of the code from each-other? Ridiculous. From Wordpress having endless entry points that output actual values and putting sensitive data in global scope permanant storage – to forum softwares leaving their settings file with all the sensitive stuff 755 (or many people resorting to 777) – to software like SMF and vBull actually trusting the array version of a set of fields in a form to actually contain just the values that should be set without even checking it against a server-side list…

I thought this stuff was programming 101 – It was twenty years ago and we didn’t even HAVE most of these languages or databases… much less as grandiose a form of networking.

Yeah, and DOS users said the same thing about *nix file permissions for twenty years. :smiley:

Uhm… modifying an objects variables when passed by reference, vs trying to write to a file that’s 644… :confused: Not even in the same county, much less ballpark. Unless of course you’re silly enough to 755 it like all the default “idiot mode” CMS settings.php files out there.

though I suppose that is a detail I omitted – settings is NOT static and some functions CAN change it…

Though no… not an option, as there will be functions that SHOULD be able to modify it and/or add to it as well… so locking it out completely doesn’t fly either.
I do not recall ever saying you cannot add means to modify the values. But now of course that seems completely counter-intuitive. You want the ability to modify but…you don’t want the ability to modify.

The same reason turdpress does? Custom Skins, custom mods, all of which make 80%+ of wordpress vulnerabilities be in what people add to the code. Hence that nice little pwnie they won back in '08? (still no excuse for all the gaping massive holes elsewhere in it though… un/pw in DEFINE? really? REALLY? REALLY?!?)
Again why are you adding untrusted code to your system? How many layers of wasteful abstraction are you going to add? When you can do the simplest thing ever, do not add untrusted code. If a user for whatever means adds untrusted code they are liable, any system you can come up with will be defeated. The bad code is already on the other side of the air-tight-hatch. You lost. So how much wasteful abstractions are you going to add for a problem that is not even a problem?

Uhm… modifying an objects variables when passed by reference, vs trying to write to a file that’s 644… :confused: Not even in the same county, much less ballpark. Unless of course you’re silly enough to 755 it like all the default “idiot mode” CMS settings.php files out there.
If PHP or the web server (Apache) has owner privileges or runs under the user the has owner privileges for the file in question a simple call to chmod will fix that. But if its already running under the owner account then it won’t matter. Now if were on a Windows server this would not be much of an issue. The nix permissions system is way too limited for my taste, having ACLs will make things so much better. (Yes I know there are third-party additions to add ACLs to nix systems)

I like how Raymond Chen puts it:
It rather involved being on the other side of this airtight hatchway

The untrusted code is already on the other side of the airtight hatchway that you are trying to so all this abstraction for.