-
201104.15
PHP finally has anonymous functions??
CommentsWow, I can't believe I missed this...nobody seems to be talking about it at all. Ever since PHP 5.3, I can finally do non-generic callbacks.
UPDATE: Check out this description of PHP lambdas (much better than what I've done in the following).
2 function do_something($value) 3 { 4 // used >= 2 times, but only in this function, so no need for a global 5 $local_function = function($value) { ... }; 6 7 // use our wonderful anonymous function 8 $result = $local_function($value); 9 ... 10 // and again 11 $result = $local_function($result); 12 return $result; 13 }
There's also some other great stuff you can do:
2 $favorite_songs = array( 3 array('name' => 'hit me baby one more time', 'artist' => 'britney'), 4 array('name' => 'genie in a bottle', 'artist' => 'xtina'), 5 array('name' => 'last resort', 'artist' => 'papa roach') 6 ); 7 $song_names = array_map(function($item) { return $item['name']; }, $favorite_songs);
GnArLy bra. If PHP was 20 miles behind Lisp, it just caught up by about 30 feet. This has wonderful implications because there are a lot of functions that take a callback, and the only way to use them was to define a global function and send in an array() callback. Terrible. Inexcusable. Vomit-inducing.
Not only can you now use anonymous functions for things like array_map() and preg_replace_callback(), you can define your own functions that take functions as arguments:
2 function do_something_binary($fn_success, $fn_failed) 3 { 4 $success = ... 5 if($success) 6 { 7 return $fn_success(); 8 } 9 return $fn_failed(); 10 } 11 12 do_something_binary( 13 function() { echo "I successfully fucked a goat!"; }, 14 function() { echo "The goat got away..."; } 15 );
Sure, you could just return $success and call whichever function you need after that, but this is just a simple example. It can be very useful to encapsulate code and send it somewhere, this is just a demonstration of the beautiful new world that just opened for PHP.
So drop your crap shared host (unless it has >= 5.3.0), get a VPS, and start using this wonderful new feature.
-
CommentsWe were writing some parsing code for a client today. It takes a long string (html) and parses it out into array items. It loops over the string recursively and running a few preg_replaces on it every pass. We got "out of memory" errors when running it. After putting in some general stats, we found that memory usage was climbing 400k after each block of preg_replaces, which was being added on each loop (there were around 600 loops or so). This memory just grew and grew, even though the recursion at most got 6 levels deep. It was never being released.
I did some reading and found that the preg* functions cache up to 4096 regex results in a request. This is the problem...a pretty stupid one too. It would be nice if they made this a configurable option or at least let you turn it off when, say, you are running a regex on a different string every time (why the hell would I run the same regex on the same string twice...isn't that what variables are for?) Unless I'm misunderstanding and PHP caches the compiled regex (but not its values)...but either way, memory was climbing based on the length of the string.
Since the regex was only looking at the beginning of the string and disregarding the rest (thank god), the fix was easy (although a bit of a hack):
$val = preg_replace('/.../', '', $long_string);Becomes:
$short_string = substr($long_string, 0, 128); $val = preg_replace('/.../', '', $short_string);PHP guys: how about an option to make preg* NOT have memory leaks =).
-
CommentsThis weekend I wen't on a frenzy. I turned beeets.com from a single VPS enterprise to 4 VPSs: 2 web (haproxy, nginx, php-fpm, sphinx, memcached, ndb_mgmd) and 2 database servers (ndmtd). There's still some work to do, but the entire setup seems to be functioning well.
I had a few problems though. In PHP (just PHP, and nothing else) hosts were not resolving. The linux OS was resolving hosts just fine, but PHP couldn't. It was frustrating. Also, I was unable to sudo. I kept checking permissions on all my files in /etc, rebooting, checking again, etc.
The fix
Then I looked again. /etc itself was owned by andrew:users. Huh? I changed permissions back root:root, chmod 755. Everything works. Now some background.
A while back, I wrote some software (bash + php) that makes it insanely easy to install software to several servers at once, and sync configurations for different sets of servers. It's called "ssync." It's not ready for release yet, but I can say without it, I'd have about 10% of the work done that I'd finished already. Ssync is a command-line utility that lets you set up servers (host, internal ip, external ip) and create groups. Each group has a set of install scripts and configuration files that can be synced to /etc. The configuration files are PHP scriptable, so instead of, say, adding all my hosts by hand to the /etc/hosts file, I can just loop over all servers in the group and add them automatically. Same with my www group, I can add a server to the "www" group in ssync, and all of a sudden the HAproxy config knows about the server.
Here's the problem. When ssync was sending configuration files to /etc on remote servers, it was also setting permissions on those files (and folders) by default. This was because I was using -vaz, which attempts to preserve ownership, groupship, and permissions from the source (not good). I added some new params (so now it's "-vaz --no-p --no-g --no-o"). Completely fixed it.
-
200911.27
Arrays: Some PHP tricks I never knew
CommentsThis will be a short post, but pretty cool.
You can add arrays together:
$test1 = array('name' => 'andrew'); $test2 = array('status' => 'totally gnar, dude'); print_r($test1 + $test2); --------------------------- Array ( [name] => andrew [status] => totally gnar, dude )Wow...who would have thought. And my most recent favorite, converting objects to events. It's a simple foreach($object as $key => $val) and putting each element into a separate array right? WRONG:
$array = (array)$object;
No fucking way. Casting actually works in this case. Why does nobody tell me anything?! This is great for parsing XML because any parser normally returns an object, and quite honestly, I hate dealing with objects. All database data is by default returned as an array usually, and it's a pain having some data sources being objects while others are arrays. Now it doesn't matter...if you like objects, cast an associative array as an (object), if you like arrays cast with (array). I love PHP...
-
CommentsI recently (read: today) had an obnoxious problem: I'm writing some code for creating an ATOM feed, and kept getting errors about entity-escaped values. Namely, things like ’, •, etc. Even written as entities, Opera and IE7 did not recognize them. I read somewhere that it was necessary to convert the named entities to numbered entities. Great.
Well, PHP doesn't have a native function for this. Why, I do not know...there seems to be functions for many other things, and adding an argument to htmlentities that returns numbered entities would seem easy enough. Either way, I wrote a quick function that takes the htmlentities translation table, adds any missing values that are not in the translation table, and runs the conversion to numbered entities. Check it:
function htmlentities_numbered($string) { $table = get_html_translation_table(HTML_ENTITIES); $trans = array(); foreach($table as $char => $ent) { $trans[$ent] = '&#'. ord($char) .';'; } $trans['€'] = '€'; $trans['‚'] = '‚'; $trans['ƒ'] = 'ƒ'; $trans['„'] = '„'; $trans['…'] = '…'; $trans['†'] = '†'; $trans['‡'] = '‡'; $trans['ˆ'] = 'ˆ'; $trans['‰'] = '‰'; $trans['Š'] = 'Š'; $trans['‹'] = '‹'; $trans['Œ'] = 'Œ'; $trans['‘'] = '‘'; $trans['’'] = '’'; $trans['“'] = '“'; $trans['”'] = '”'; $trans['•'] = '•'; $trans['–'] = '–'; $trans['—'] = '—'; $trans['˜'] = '˜'; $trans['™'] = '™'; $trans['š'] = 'š'; $trans['›'] = '›'; $trans['œ'] = 'œ'; $trans['Ÿ'] = 'Ÿ'; $string = strtr($string, $trans); return $string; }Hope it's helpful.
UPDATE - apparently, even the numbered entities are not valid XML. Fair enough, I've converted them all to unicode (0x80 - 0x9F). All my ATOM feeds validate now (through feedvalidator.org).
-
200901.16
Amazon S3
CommentsVery cool service. I updated beeets to pull all images from images.beeets.com, an S3 bucket. Also, all css files now go through /css/css.php/file.css which rewrites
url(/images/...)
to
url(http://images.beeets.com/images/...)
And guess what, it all works. I had some bad experiences with the S3Fox firefox plugin in the past, but it's since been updated and I've been using it regularly.
Also, using S3.php, all profile images now go directly onto images.beeets.com. Wicked.
So what does this mean? A few things:
- Less bandwidth & work - beeets will spend more time serving HTML, CSS, and JS than images.
- Safer - We were backing up profile images to S3 indirectly before, but the chances of S3 going down VS our hosting are slim.
- Worse image caching - Before, I had .htaccess controlling all the caching for static files. I liked it that way. S3 doesn't do this very well at all. Apparently it's configurable, but I don't know how...any ideas?
All in all, it should be better for beeets. Maybe we'll actually let users have images bigger than 10x10 now ;)
Thumbs up to S3 (and probably all other Amazon web services).
-
CommentsWow. You'd think it would be easy. In fact, it should have been. Compile a module, load it from apache. Recompile PHP with --enable-fastcgi...oh wait, I already had it in there (always thinking ahead!!). Change some apache settings.
Right? Yeah, right. It took two days. I can't even really remember why. The biggest problem was that running make && make install in the mod_fastcgi source was NOT yielding a 'mod_fastcgi.so' as the documentation PROMISED! In fact, it installed mod_fastcgi.la instead, a highly useless file.
So how did the master get out of this bind? Beats me, try asking him. As for me, I had to run 'ld -Bshareable *.o -o mod_fastcgi.so' which is mentioned in some document from a long time ago in a galaxy far, far away.
Let me interject and say that the information on the FastCGI website is "not very well documented."
Day 2. I figured, what's the point of FastCGI if it's not set up to connect to a remote App server? Maybe I don't HAVE an external server set up, but we can pretend. Well that's another nightmare. There's a good external FastCGI guide written about it, and guess what it worked. Not really a nightmare at all, come to think of it. Quite pleasant.
All in all, shouldn't have taken 2 days =P (I'm a tinkerer)...but fuck it, I have FastCGI now, ready to connect to all those App servers I have churning away in the background (one day).
In all the excitement, I also compiled and installed the apache worker-MPM. A few tests with ab didn't really show any noticeable difference. But threads are cool, right?
Next up: figure out how to configure Apache to pass all requests ending in .php (whether the file exists on the web server or not) to our "app" server. Is this possible?
-
200901.14
IIS and PHP
CommentsSo tonight I helped a client set up PHP5 on IIS 7 using MSSQL 2005. These things always work great in theory but judging my my use of the word "theory" in italics, you can probably guess that things weren't so smooth in practice.
The client was smart enough to get FastCGI working through IIS...something I would have probably rolled over on. From then on, it was an upward battle getting a simple PHP prototype project going.
In the later versions of PHP 5, it would seem that all mssql_* functions have...been... removed? There is an ntwdblib.dll that needs to be replaced to play nicely with mssql 2005...but it doesn't exist in the latest releases. How strange. I ended up reverting to 5.2.5, making me a not-so-bleeding-edge pushover :'(. It's cool though.
Then MSSQL doesn't accept normal logins, only windows ones, and it's bloomin' impossible finding out how to change that.
One thing Microsoft seems to have actually done right is release a rewrite module (much like mod_rewrite) that you don't have to frickin' pay for, which is nice. On a side note, I really hated Windows Server 2008. It's like Vista in every way, except that the design is slightly different, somewhat. Sorry, MS, but get your shit together plz, kkthxbai.
Anyway, we got everything going. What a pain in the ass though!
If you're wondering, I'm more of a Unix guy ;). And yes, I have used a computer before.