The SitePoint Forums have moved.

You can now find them here.
This forum is now closed to new posts, but you can browse existing content.
You can find out more information about the move and how to open a new account (if necessary) here.
If you get stuck you can get support by emailing forums@sitepoint.com

If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

This bit of code will change any $_POST array variable (is that the right way to explain that?) with a value of 'on' to 'Yes'. I did this because checkboxes return "on" when they are checked, and I wanted "Yes" to be in the database, not "on".

After thinking about it, this bit of code would work only as a way to change every key with a specific value to another value... So disregard my bit of code for echoing!!.

Well, my point was that you can't loop through the $_POST array using a number for the key (at least, it wasn't working for me).

I'm totally aware of that. But the difference between my foreach-loop and your for-loop is
that in your loop the same value is echoed everytime, whereas my loop actually traverses
the $_POST-array. But then, you set yourself straight. :-)

By the way, more often than not you can't use foreach, even though it seems nice. When
doing this:

PHP Code:

foreach ($array as $key => $value) { ... }

$key and $value become copies of the current array element that changes at each
iteration of the loop. The problem arises when you store objects (or references) inside an
array. With foreach you get a copy of every object, and not a reference to it, so
calling a method on an object that changes its state has no effect. E.g.:

This doesn't work! It's extremely sad, but that doesn't make it less true.

I think the problem stems from the difference between 'passing by value' and 'passing by
reference'. Compared to Java, PHP does things a bit different. (In Java, there is no
difference; parameters are always passed by value.)

'Passing by value' in Java means that when you assign a value to an argument inside a
function, the value won't change on the outside. This is the same as in PHP. For example:

PHP Code:

function test($i)
{
$i = 12;
}

$i = 8;
test($i);
echo $i; // prints '8'

Now comes the difference between Java and PHP. In Java, objects are always passed
by value, but you can call methods on an object inside a function that changes its value.
For example (Java):

PHP Code:

void setValue(Object o, Value v)
{
o.setValue(v);
}

To be explicit: the object 'o' is passed by value, but it is still possible to call a
method on it that changes its inner state.

In PHP this doesn't work: you'd be changing the value of a copy of the object, and
not of the original object. To solve this problem, you must pass the object by
reference, as in this example:

PHP Code:

function setValue(&$object, $value)
{
$object->setValue($value);
}

However, there is a problem. It is now possible to do this:

PHP Code:

function setValue(&$object, $value)
{
$object = new Object($value);
}

Which isn't very nice (because all other properties of the passed object are lost). The
only way to overcome this problem is by following programming rules like this one:
'Never assign to references passed to functions.'. Generally, it is considered bad
practice to assign to any parameter passed to a function, be it passed by value or
by reference, so this rule shouldn't too hard to follow, but still it's something you
have to enforce on yourself.

I won't say that PHP's approach to passing by value is bad, or that Java's approach is
better. PHP looks a lot more like C(++) than Java, and I personally prefer C++ above
Java (but I hate C). It's just a design decision, and one you should be aware of!

To conclude: when you use objects in PHP, you should always pass (and return!) them
by reference. When storing objects (or references) inside an array, don't use foreach to
iterate over the array elements, but use some other method instead. (See the Annotated PHP
Manual for more information on how to do this.)

converting script to no longer use globals

Does anyone know of a simple script to help fix up scripts that use globals? I've been beavering away on a PHP/MySQL site using Kevin's book which taught how to do everything using globals (not his fault...the deprecation of globals is new since he published). This leaves me with a large number of scripts which use both GET and POST globals from links and forms. Is there a script I can use to debug my scripts. Something that will list all of the globals accessed in the script and the "type" of global...ie: post or get? Can I use $GLOBALS? How?

Philip, i don't know of an automated way to fix your scripts. also, since well more than a year ago, $HTTP_*_VARS has been available and has been the preferred way to access variables. Kevin's book should've used those.

BTW, i don't think that first bit of code will do anything except display all the variables that are defined. in the second bit, use the second method if you want to "shorten the name":

Zaire, extract() will do the same thing. using either method defeats the purpose of not using register_globals, though. any variable that a user specifies will be introduced as a global variable! i want NO variable in my scripts that i didn't create (except for the predefined ones).

Clarification

Hi Larry!

I just want to make sure I understand here...before I go and assualt the dozens of scripts I have to update.

Will the following script display a list of all global variables defined in my script? I want to use it to quickly help me identify all the variables that are coming into the script. Or will it just call up the list of variables currently being passed in the current page request? I know that may sound a little silly, but I have A LOT of scripts to update and I want to do it as efficiently as possible.

I get the feeling that the only way to do this right is the hard way. Line by line making sure that nothing improper is being passed to the script.

Finally, I just want to make sure I am clear on this before moving ahead. Here's what I am going to do. Can you tell me if this is right?

[list=1][*]Identify all variables that will are passed to a given script[*]Convert to safe versions using $var = $_GET['var'] or $var = $_POST['var'][*]scratch my head and wish I had done this in the first place[/list=1]

Another stupid question here. Why does converting the variables and using $_GET and $_POST help avoid security problems? I need help understanding how this works. Why does this stop a hacker from just entering in a bogus URL in order to spoof the variables. For example, if the following URL passes the variable $id:

Won't the resulting contents of $id still be whatever was in the address bar when the URL was submitted in the browser? For that matter, how does the $_POST trick protect things? Even if a hacker makes up their own form and hits the script with data, doesn't $_POST just convert whatever was sent it's way or does it actually check that it came from the right source?

Sorry to ask these silly questions, I just want to understand the "how it works' side of this security issue. It'll make me clench my teeth less when I am spending hours rewriting code I just finished!

This registers the $username and $password variables in the session. If instead you use session_register with register_globals = off, you get strange things happening like the session variable doesn't become avaiable to the script that registered it.

If you don't do a 'session_start()' at the beginning of the script, no session data will be saved (when register_globals are off). This is true for PHP 4.2.0 on Windows and Unix.

If you follow the manual, you should never use any of the 'session_'-functions any longer, and you should only read from and assign to the $_SESSION-array. Without calling mentioned 'session_start()', this won't work, contrary to what the manual says!

Maybe in the NEXT version of PHP this will be solved...

BTW: in PHP 4.1.2 on Windows, sessions didn't work at all (with 'register_globals = off'). This caused some serious headaches, as you can imagine. Everything worked well on Unix, but it didn't on Windows. Now what? Nothing on http://bugs.php.net, so it must have been my fault... But no: install 4.1.1 or 4.2.0 and everything works again. Very nasty, those kinds of bugs...

Philip, like i said, i think your "GLOBALS" code will display ALL variables that are defined, not just get/post/cookie ones. so if you had `$foo = 'bar';', $foo would be printed too.

assigning by reference makes both variables point to the same data rather than making a copy of the data. so since they both point to the same data, if you change one variable, you change both. but for trying to use a shorter variable name like in your example, there's no need to make a copy and a reference will be faster.

your steps sound correct.

about the security stuff. when register_globals is off, it doesn't matter how many variables a hacker tries to add in the URL/form/cookie, they will stay in the $_* arrays doing no harm unless you access them. when register_globals is on or you extract() the arrays, any variable that is supplied will be in your script, even though you never expected it to be. however, as i said, when they're in the arrays, they'll never affect anything! it's OK to do

$id = $_GET['id']

and i do all the time, because YOU are creating the $id variable, and you know it's from the URL since it's in the $_GET array. again though, if register_globals is on or the arrays are extract()ed, and you never used $id in your script, it would be created if `id=' was put in the URL. that's exactly what i don't want.

i hate that these global variables were ever created. it's just wrong IMO to not know where user variables came from. they should be confined to something like an array to keep them harmless; and they are when register_globals is off and you access them via these arrays -- the way, and only way, it should've been all along.

If code is properly, and securely written, register_globals won't present a problem.

The problem is when developers don't check their variables.

PHP coders (myself included) are lazy. We don't have to worry about garbage collection, or memory allocation (for the most part), so we also let down our collective guard when it comes to variables/input, and that's why register_globals is a bad thing (usually).

It's the same reason we add slashes to any data we're sending to the database, and why we escape command characters when it comes to calling the system/shell.

That said, it IS possible to maintain security while using register globals.

I have a template (init_admin) that is called before the regular init template. It sets up some admin data.

init checks to see if $ADMIN_INIT is true, if so, carries out some admin-related code.

To make sure $ADMIN_INIT was set by me, and not by my client, I do something like this:

But with is off, only $_SESSION[logged_in] is acceptable, not $_GET[logged_in]

The other reason is one of making code make sense. With globals on, variables can be declared all over the place, and with big projects, with many files included and PHP classes, you cna have a nightmare bug fixing and updating code.

[added]
Checked out our favorite search engine (google) for the answer and found this post from PHPBuilder.com

there is a minute (and I do mean minute) speed difference between print and echo. Print is a function and returns a value (not a very useful one, but it returns a value nonetheless) and therefore takes just a little more time processerwise than echo, but for the most part, it is splitting hairs to tell the difference.

Errr... well in my opinion sessions have a different purpose to cookies. But perhaps this is worth a tip;

Use sessions for users currently actively browsing your website. Sessions are there to store data that's required for the users current visit. For example storing their username / password for your sites authentication system.

Use cookies for long term data which you want to survice between visits by an individual users. For example you store their name in a cookie so that next time they come to your site, you can display "Welcome back HarryF!". The cookies would then "hand off" their data to the sessions for the current visit.

PHP: Hackers Paradise Revisited

Stumbled upon this article today, from April 4th, 2001 (but it's still very applicable to the latest versions).

Full of healthy goodness like;

It seems strange to think of a web programmer as lazy. Last year most of us were working 100 hours a week to join the gold rush, now we are doing it at reduced pay just to stay afloat. In fact, we need to be lazy because we are so busy.

There are two key ways to be lazy. Firstly always use existing code when it is available, just integrate it into your standards and project. The second technique is to develop a library of helpful functions that let you be lazy in the future

And

The hardest thing for me to learn as a web programmer was to change the way I wrote code. Coming from a product development and university background the emphasis is on doing it the right way. Products have to be as close to perfect as possible before release. School assignments need to be perfect.

The web is different. Here it is more important to finish a project as soon as possible than it is to get it perfect first time. Web sites are evolutionary, there is no freeze date after which it is difficult to make changes.

I like to think of my web sites as prototypes. Everyday they get a little closer to being finished. I can throw together 3 pages in the time it would take to do one perfectly. It's usually better on the web to release all three and then decide where your priorities lie. Speed is all important.

So, everything you do as a programmer should be focused on the speed at which you are producing code (pages).

Checking equality and existence

A few tips from an overworked coder.

Don't use if($foo == "bar") if $foo happens to be a string...it's better to use if(strcmp($foo, 'bar')) instead.

if($foo) is a bad idea as well, especially if you have your error reporting turned to E_ALL(which you should) - instead try using if(isset($foo)) or if(!empty($foo)) or both if you need to check whether it's set AND empty

for coders who work with designers, or just for an easy system to change the design of a site with a single variable, check out http://smarty.php.net smarty is a FAST and EASY template system that uses two(optionally three) classes, just drop and go

the BEST way to comment code is to use the phpdoc format - check Pear (The Php Extension and Application Repository at http://pear.php.net/) for more info on coding standards and commenting standards

Finally, you can eek a bit more speed out of your code, especially if you have LOTS of strings, by using single quotes and concanetating variables in (I can't spell today...sigh)

$string = 'this is a string with '.$foo.' in it';

it's marginally faster than

$string = "this is a string with $foo in it";

the reason is php has to search through the string to find the variable...if you've been coding for a while and are used to the double it's not a big deal, but for those who are newbies (this is a newbie tips place, right?) it's good to learn to code right the first time instead of having to retrain or *gasp* learning bad habits.

let's see......mysql tips as well? mysql 4.0 kicks the pants off of the old mysql, upgrade if at all possible (foreign keys are coming!)

I know this has been said before, but to reiterate

REGISTER GLOBALS IS EVIL!!

single biggest cause of problems is right there....always use the HTTP_POST_VARS or better yet the $_POST, $_GET, etc. (server, session, etc, you get the drift)

ALWAYS clean user input - here's a snippet I happen to use for all my forms