An improved generic caching function Thu Jul 29 15:00:02 2010
You may remember my generic caching function from a while back.
One of the things I struggled with a little bit was coming up with a key for anonymous functions. I ended up using the SPL ReflectionFunction class to come up with a unique hash for a function and argument list. I happened upon a better solution earlier today: spl_object_hash(). Because PHP's anonymous functions are actually an instance of the (internal) Closure class, they can be hashed no problem.
Here is the updated function:
Usage remains exactly the same.
One of the things I struggled with a little bit was coming up with a key for anonymous functions. I ended up using the SPL ReflectionFunction class to come up with a unique hash for a function and argument list. I happened upon a better solution earlier today: spl_object_hash(). Because PHP's anonymous functions are actually an instance of the (internal) Closure class, they can be hashed no problem.
Here is the updated function:
<?php
function createCached($fn, $ttl = 100){
return function() use($fn, $ttl){
$args = func_get_args();
if (!is_string($fn)){
$key = md5(spl_object_hash($fn).serialize($args)); //This is the bit that's changed
} else {
$key = md5($fn.serialize($args));
}
$result = apc_fetch($key, $success);
if ($success) return $result;
$result = call_user_func_array($fn, $args);
apc_store($key, $result, $ttl);
return $result;
};
}
function createCached($fn, $ttl = 100){
return function() use($fn, $ttl){
$args = func_get_args();
if (!is_string($fn)){
$key = md5(spl_object_hash($fn).serialize($args)); //This is the bit that's changed
} else {
$key = md5($fn.serialize($args));
}
$result = apc_fetch($key, $success);
if ($success) return $result;
$result = call_user_func_array($fn, $args);
apc_store($key, $result, $ttl);
return $result;
};
}
Usage remains exactly the same.
Find big files on a linux box Wed Jul 7 9:21:52 2010
What's that, young man? Oh, you're a woman? I am sorry... Anyway; what was it you wanted? You're running out of disk space and you want to find all the big files on your linux machine so you can blindly delete them? Try this:
You're welcome.
find / -type f -size +20000k -exec ls -lh {} \; | awk '{ print $9 ": " $5 }'
You're welcome.
Easy Bread - slightly plagiarised from Jamie Oliver Wed Jun 30 13:14:32 2010
A little change from the usual (hah!) posts. Bread is awesome, and it's even more awesome when it's fresh. I've been making my own recently, and you know I love to share.
This isn't completely stolen from Jamie Oliver - I knicked the basic recipe, simplified it somewhat and took out numerous references to things being 'pukka'.
Ingredients for a medium sized loaf, or two pizza bases
--------------------------------------------------------
10.5g of dried yeast
15g of sugar
250g of plain flour
250g of strong white bread flower
290ml / ~half pint of warm water
1 teaspoon of salt
Optionally: pizza toppings (see point 10 onwards)
0. Mix the yeast, water and sugar together in a jug, big glass, small bowl or
whatever you have to hand.
1. Put everything else (all the flour and the salt) into a big bowl and mix it
up a bit. Bonus points if you sieve the flour on the way in.
2. Pour the liquid from step 0 into the flour and mix it up until it starts to
look a bit like dough.
3. Spread flour all over your work-surface, tip the dough onto it and knead
it for about 5 minutes. Put some effort into it, dammit!
4. Put the dough in a tin dusted with flour, cover it (with clingfilm a tea-towel),
and put it somewhere warm for 45 minutes.
5. Your dough should have doubled in size. Put it back on your flour-covered
work-surface and beat the crap out of it for two minutes; really - releave
some stress.
6. Put your dough in your chosen container. For pizza, roll it out nice and
thin and put it on a baking tray.
7. Cover and put it back in your warm place to rise again. 10 minutes for
pizza, 45 minutes for a loaf.
8. Cook on a middle shelf at about 200 degrees celcius. ~5 minutes for pizza,
15-20 minutes for a loaf. Just keep an eye on it and use your judgement.
9. If you're making a loaf, you're done! For pizza, leave it to cool a bit
and get ready to make some toppings.
10. Mix up some salt, pepper, oragano, tomato puree, barbeque sauce, tomato
sauce and olive oil. Taste it. Make sure it tastes good.
11. Spread your tasty sauce from step 10 all over the base and then throw some
mozzarella on top of it.
12. Cut up some peppers, sausage, bacon, whatever - try not to go mental with
it. Throw all that on top of the mozzarella.
13. Throw it back in the oven for about 10 minutes. Same heat.
14. I refuse to put 'enjoy' as the last step. EAT IT, YOU IDIOT!
Once you've got the basic recipe and technique down, innovate with it and make awesome stuff. Put some olive oil, garlic and herbs on your bread just before step 7, mash it with your fingers and make some focaccia.
This isn't completely stolen from Jamie Oliver - I knicked the basic recipe, simplified it somewhat and took out numerous references to things being 'pukka'.
Ingredients for a medium sized loaf, or two pizza bases
--------------------------------------------------------
10.5g of dried yeast
15g of sugar
250g of plain flour
250g of strong white bread flower
290ml / ~half pint of warm water
1 teaspoon of salt
Optionally: pizza toppings (see point 10 onwards)
0. Mix the yeast, water and sugar together in a jug, big glass, small bowl or
whatever you have to hand.
1. Put everything else (all the flour and the salt) into a big bowl and mix it
up a bit. Bonus points if you sieve the flour on the way in.
2. Pour the liquid from step 0 into the flour and mix it up until it starts to
look a bit like dough.
3. Spread flour all over your work-surface, tip the dough onto it and knead
it for about 5 minutes. Put some effort into it, dammit!
4. Put the dough in a tin dusted with flour, cover it (with clingfilm a tea-towel),
and put it somewhere warm for 45 minutes.
5. Your dough should have doubled in size. Put it back on your flour-covered
work-surface and beat the crap out of it for two minutes; really - releave
some stress.
6. Put your dough in your chosen container. For pizza, roll it out nice and
thin and put it on a baking tray.
7. Cover and put it back in your warm place to rise again. 10 minutes for
pizza, 45 minutes for a loaf.
8. Cook on a middle shelf at about 200 degrees celcius. ~5 minutes for pizza,
15-20 minutes for a loaf. Just keep an eye on it and use your judgement.
9. If you're making a loaf, you're done! For pizza, leave it to cool a bit
and get ready to make some toppings.
10. Mix up some salt, pepper, oragano, tomato puree, barbeque sauce, tomato
sauce and olive oil. Taste it. Make sure it tastes good.
11. Spread your tasty sauce from step 10 all over the base and then throw some
mozzarella on top of it.
12. Cut up some peppers, sausage, bacon, whatever - try not to go mental with
it. Throw all that on top of the mozzarella.
13. Throw it back in the oven for about 10 minutes. Same heat.
14. I refuse to put 'enjoy' as the last step. EAT IT, YOU IDIOT!
Once you've got the basic recipe and technique down, innovate with it and make awesome stuff. Put some olive oil, garlic and herbs on your bread just before step 7, mash it with your fingers and make some focaccia.
Real-ish paths without realpath() Wed Jun 30 12:11:08 2010
Every once in a while you might find the need to resolve the 'double dots' in a file path, but if the file doesn't exist (perhaps you are about to create the file) you can't use PHP's realpath().
If all you want to do is resolve the 'double dots' in a path, you could do so like this:
Note that it is unable to resolve pathnames any higher than the present working directory. I.E. It doesn't know about any directory names that you don't tell it about; hence: ../../foo becomes foo.
The alternative would be to touch() the file, call realpath() and then unlink() the file. Something about that just feels dirty though - you have to be careful with the unlink() step, and if you don't want to resolve symlinks it won't do you any good.
If all you want to do is resolve the 'double dots' in a path, you could do so like this:
<?php
function resolveFilename($filename)
{
$filename = str_replace('//', '/', $filename);
$parts = explode('/', $filename);
$out = array();
foreach ($parts as $part){
if ($part == '.') continue;
if ($part == '..') {
array_pop($out);
continue;
}
$out[] = $part;
}
return implode('/', $out);
}
assert(resolveFilename('/srv/home/../../etc/./passwd') == '/etc/passwd');
assert(resolveFilename('/srv/home/foo') == '/srv/home/foo');
assert(resolveFilename('../../foo') == 'foo');
assert(resolveFilename('/foo//bar') == '/foo/bar');
assert(resolveFilename('bar') == 'bar');
function resolveFilename($filename)
{
$filename = str_replace('//', '/', $filename);
$parts = explode('/', $filename);
$out = array();
foreach ($parts as $part){
if ($part == '.') continue;
if ($part == '..') {
array_pop($out);
continue;
}
$out[] = $part;
}
return implode('/', $out);
}
assert(resolveFilename('/srv/home/../../etc/./passwd') == '/etc/passwd');
assert(resolveFilename('/srv/home/foo') == '/srv/home/foo');
assert(resolveFilename('../../foo') == 'foo');
assert(resolveFilename('/foo//bar') == '/foo/bar');
assert(resolveFilename('bar') == 'bar');
Note that it is unable to resolve pathnames any higher than the present working directory. I.E. It doesn't know about any directory names that you don't tell it about; hence: ../../foo becomes foo.
The alternative would be to touch() the file, call realpath() and then unlink() the file. Something about that just feels dirty though - you have to be careful with the unlink() step, and if you don't want to resolve symlinks it won't do you any good.
Getting raw POST data with PHP Sun Jun 27 23:09:52 2010
John McLear asked me to come over and help him out with some XML-RPC stuff he was working on last week, and the question of how to get raw POST data with PHP came up. I didn't know off the top of my head, and it took a little while to figure / find out, so I thought I would share.
In the old days (oh what dark days they were), there was a special variable you could use to get the raw POST data: $HTTP_RAW_POST_DATA. In these modern times, PHP's input and output streams (you know, the php:// ones) provide the handy-dandy php://input stream, just for getting the raw POST data. The input streams can be passed to a bunch of different functions, but the easiest to use is probably file_get_contents.
I think this little snippet demonstrates nicely:
Pop that into a PHP file on your webserver, view it, hit the Submit button and you should see something a little like this displayed before the form:
Oh look! It's raw POST data! :-)
But, what is it good for?
I admit, this kind of thing is of limited use in most people's day to day work, but if you've got XML being fired in a POST request at your script, you don't really have much of an alternative.
In the old days (oh what dark days they were), there was a special variable you could use to get the raw POST data: $HTTP_RAW_POST_DATA. In these modern times, PHP's input and output streams (you know, the php:// ones) provide the handy-dandy php://input stream, just for getting the raw POST data. The input streams can be passed to a bunch of different functions, but the easiest to use is probably file_get_contents.
I think this little snippet demonstrates nicely:
<?php
echo file_get_contents('php://input');
?>
<form action="#" method="post">
<input type="text" name="textOne" value="Foo"/>
<input type="text" name="textTwo" value="Bar"/>
<input type="submit" value="Submit"/>
</form>
echo file_get_contents('php://input');
?>
<form action="#" method="post">
<input type="text" name="textOne" value="Foo"/>
<input type="text" name="textTwo" value="Bar"/>
<input type="submit" value="Submit"/>
</form>
Pop that into a PHP file on your webserver, view it, hit the Submit button and you should see something a little like this displayed before the form:
textOne=Foo&textTwo=Bar
Oh look! It's raw POST data! :-)
But, what is it good for?
I admit, this kind of thing is of limited use in most people's day to day work, but if you've got XML being fired in a POST request at your script, you don't really have much of an alternative.