A dirty tale from the real world ...

Posted by Felix Geisendörfer, on Jan 16, 2008 - in PHP & CakePHP » Other

Deprecated post

The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.

Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.

Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).

Oh boy ... tonight was fun. I'm fairly busy getting PostTask.com launched (yeah, you don't need a pw for it anymore but give us a couple days before announcing public beta), and here comes the real world hitting me perfectly in the face.

A long time ago I did a little CMS for the hotel website for my step father. It was one of my first real cake apps and given that fact in retro-perspective pretty bad. I was experimenting with too many ways to use CakePHP at once and kind of ended up with a messy app. Anyway, after some weeks of occasional bug fixing it ended up working fine so I never worried much about it.

Until a couple days ago ... when the hoster updated from PHP 4.4 to 4.8 for security reasons. Don't get me wrong, I don't blame them for doing this, unfortunately this server update broke a component that this site depended upon, TextilePHP. The site uses textile for everything and the hotel suddenly was unable to update anything on it, resulting in ~5++ potential guests complaining every day about no current event schedule to be online.

I spend lots of time debugging the TextilePHP script, but I finally gave up. The thing is a 4000 line beast, full of the craziest regex, cryptic code and other goodies and multiple things where failing in it at once - not one of them I which I was able to diagnose properly (apache dying in a seg fault w/o any hint of an error sucks).

So what's the solution? Replacing the component with another one is no option - there simply isn't any compatible one out there. Removing the component? Not an option either - all contents of the site are written and stored in textile. Luckily I did decide to cache the parsed textile as an 'html' field in the db tables, so displaying old content still worked - just updating didn't. So I theoretically could have moved from textile to straight HTML - but this would have been worse then rewriting the textile parser from scratch. I would have had to be the support bitch for the client trying to input html for the rest of my life - noooooo good!

Ok, so come on people. Think Web 2.0. Think dirty. Think web services. : p ... Enough clues? If not read on.

At some point I was close to setup the old PHP version on my VPS, and move the site there. A pain in the ass, but most likely a solution that would work. Then I stopped and figured: Why move the entire site, if all you need to be moved is the Textile parser? And so thats what I did. I tried a couple of servers that I had to my disposal and finally a friend had one that ran the parser like a charm. So my evil plan turned into reality. I replaced the old TextileComponent with a new version:

php
  1. // Old version:
  2. vendor('textilephp'.DS.'Textile');
  3. class TextileComponent extends Object{
  4.     function toHtml($textile, $utf8 = true) {
  5.         $Textile = @new Textile(array('flavor' => 'html/css'));
  6.         if ($utf8==true) {
  7.             return utf8_encode($textileClass->process(utf8_decode($textile)));
  8.         } else {
  9.             return $textileClass->process($textile);
  10.         }
  11.     }
  12. }
  13.  
  14. // New version
  15. uses('http_socket');
  16. class TextileComponent extends Object{
  17.     function toHtml($textile, $utf8 = true) {
  18.         if ($utf8) {
  19.             $textile = utf8_decode($textile);
  20.         }
  21.         $Socket =& new HttpSocket();
  22.         $html = $Socket->post('http://secret-server/textilephp-service/', array('textile' => $textile, 'pw' => 'secret'));
  23.         if ($utf8) {
  24.             $html = utf8_encode($html);
  25.         }
  26.         return $html;
  27.     }
  28. }

And deployed this little script on the server of my friend:

php
  1. if (!isset($_POST['pw']) || $_POST['pw'] != 'secret') {
  2.   die('Access Denied!');
  3. }
  4.  
  5. define('DS', DIRECTORY_SEPARATOR);
  6. define('ROOT', dirname(__FILE__).DS);
  7. require_once(ROOT.'textilephp'.DS.'Textile.php');
  8.  
  9. $post = isset($_POST['textile'])
  10.   ? $_POST['textile']
  11.   : "h1. Error: Param not set!\r\n\r\n";
  12.  
  13. $Textile = @new Textile(array('flavor' => 'html/css'));
  14. echo @$Textile->process($post);

The site is now up and running again and I can focus on work thats actually fun again. But what can we learn from this post?

  • Trusting some random 4k snippet of OS maintained by a single person that produces PHP warnings / notices is a bad idea
  • Doing business with friends & family is a bad idea - they'll be able to track you down ; p
  • This is a ugly hack - don't try this at home!
  • If you build your apps properly, you'll easily be able to later outsource tasks, if necessary even to 3rd party web services
  • A weblog can be used to deal with the feeling of guilt

Sorry if you where expecting something actually useful, but I just had to post this to be able to sleep tonight ; ).

-- Felix Geisendörfer aka the_undefined