Wednesday, July 07, 2010

Colonary Surgery

I don't get the opportunity to do a vast amount of XML parsing, but when I do I use SimpleXML because it's normally built into PHP and is just so...well, simple. Unfortunately, there are some things SimpleXML can't handle. One of these is colons in tag names. Google's API's use colons in abundance, such as when giving the ID of a YouTube video: <yt:videoid>.


For now, I don't have time to learn another parser, so here's a quick and dirty solution I found in a few places on the web: remove the colons!

$newXmlStr = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $xmlStr);


Works well for me, though I'm sure if you are one of those who parse vast amounts of XML, this solution would be too low-performance. But for the occasional fetching of a YouTube video or Picasa album, it can be a very useful line of code.

Labels: , ,

Wednesday, December 16, 2009

Foreach His Own

I quite often use the foreach() loop in PHP to easily modify an array by passing the array elements by reference, like so:
$testArray = array('one','two','three');

foreach($testArray as &$v) {
// whatever
}


But today this got me into a little trouble. The variables created by the foreach() loop, whether passed by reference or not, continue to exist after the loop has been closed. Thus in the previous example, after the loop is finished $v will continue to point to the last element of $testArray, by reference. Using another foreach() with the variable $v will alter the values in $testArray.
$testArray = array('one','two','three');

foreach($testArray as $k => $v) {
echo "$k: $v<br />";
}

foreach($testArray as &$v) {
// whatever
}

foreach($testArray as $k => $v) {
echo "$k: $v<br />";
}


In this example, the first foreach() echoes the original content of the array. The second foreach() does nothing except pass the array elements by reference. The third foreach() attempts to echo the content of the array but inadvertently alters its last element.

Output:
0: one
1: two
2: three
0: one
1: two
2: two


The first foreach() uses $v to store values and thus leaves it containing the value of the last element of the array. The second foreach() uses $v to hold references and thus leaves it containing a reference to the last element of the array. The third foreach() tries to store values in $v just like the first one did, but this time it contains a reference, so the values are actually stored in the last element of the array, overwriting whatever value was there before.

To make sure this doesn't happen to you like it did to me, simply unset the variables your loops use for references:
foreach($testArray as &$v) {
// whatever
}
unset($v);

Labels:

Monday, August 04, 2008

The Threat of shell_exec()

Just built a website? Think it's safe? If you're using shared hosting, think again. On many shared servers, it's a cinch to get a list of every file the web server can see, including configuration files. Hey and guess what, if you've got the config files for every site on the server, you know every site's database login credentials and could wipe out all their data or, better yet, make yourself admin accounts on every site. Everyone on your server has this power.

Are you vulnerable? Try it and find out. Log into your FTP account, and create (or find) a web accessible directory that is also world-writeable. Make a PHP file in that directory and put this in it (btw, this is Linux specific):


<?php
$f = fopen('list.txt',w);
if (fwrite($f,shell_exec('ls -AR /'))) echo '<a href="list.txt">download list</a>';
fclose($f);
?>


This is a big task, so on servers with lots of sites it could time out. You may want to try "echo shell_exec('pwd')" first, so you know what directory the sites are hosted in, and then change the ls command to only read that directory (i.e., 'ls -AR /www' instead of 'ls -AR /'). Or maybe even remove the 'R' from the command.

Now go through that list looking for config files, and try some file_get_contents(). ;-) (Actually, don't do that. You could get in trouble.)

Labels: