Here on HN everyone seems to like a good story (despite that maxim about anecdotes and data).
This year, I had to maintain legacy PHP code powering a custom calendar & training-session signup app. Notable horrors I encountered:
- Despite being written by a programmer in the employ of a major Californian company providing security solutions to corporate customers, all passwords were stored in plaintext in the database. The database itself was password-protected by a guessable variation on the company’s name (seriously).
- The ancient register_globals directive was on — not just on, but relied upon. As in, when I moved the code to a server with the directive off (e.g. any modern hosts), all the forms broke. For those who haven’t heard of this, er, “feature,” it means that any variable in the request, be it a cookie name, a GET parameter, or a POST key (that is, the name of an input field on a web form, typically) automatically becomes a global variable in the PHP script set to the provided value. So I could manipulate my DOM, add an <input> field named, say, "is_admin", set its contents to "1", and voilà! $is_admin is now truthy.
- Nothing was ever properly escaped. Not the database, not email headers, not page output.
- And of course, code and HTML were strewn together willy-nilly, with lots of repetition and insane spaghetti-code execution. Let’s just say it was non-trivial to skin all the pages in the app.
I know and you know PHP doesn’t force anyone to commit these sins. But for backwards-compatibility reasons, it still permits them… and I find it hard to believe absolute stinking dangerous messes like this are more common in other modern platforms.
Sound like pretty much every single inhouse developed or extended app after a few years/personnel replacement cycles. Yeah it sucks to work on. Apart from the register globals, it says nothing about PHP though.
Actually while I won't defend register globals in 2010, back in 1998 (am yes, I wrote PHP code in 1998) when nobody understood web development really (do we even today?) it was a handy feature, that prevented much line noise on pages that were (back then) usually composed of html with a few <? ?> tags and code in between, pretty much the way javascript was on pages until a few years ago. It was only as the php became heavier and was moved in to common include files and later into libraries that the usefulness went away (but the potential issues remained).
Despite you saying "backward compatibility", the only one of those things that has anything whatsoever to do with php is register globals. All the other ones are programmer choice, and have nothing to do with "backward compatibility". But it does sound like quite a horror story.
When using Ruby, you're using Ruby on Rails 95% of the time ... which means database access is most often than not properly escaped (it's the API's default, and according to the path of least resistance, people rarely do string concatenation for sql queries).
When using Python's Django (mostly a default nowadays) all string output in templates is escaped by default (you've got to make it explicit if you don't want it). Also in Django all forms submitted are protected against csrf attacks by default.
In no case above are you allowed to do "; drop table users", since most ORM's that were made by people with brains can detect that you want to do a DDL when a SELECT is expected. You've got to use the raw Python DB API for that, and that's not easier than just going along with what the framework gives you.
E.g. Django 1.2 added raw queries, but this will trigger an error since it is not a plain SELECT:
Users.objects.raw("DELETE FROM users")
Without a framework like Django, you can't really do web development in Python without blowing your brains out.
Every other popular web platform isn't like PHP which is a language specifically made with clear hooks for processing requests / spitting out HTML (right there, in the language).
Heck, you can't even write a PHP script that doesn't contain a "<?php" tag.
I'm not saying that bad code isn't universal, but PHP makes it a whole lot easier to do stupid things and not in a Lisp-esque way.
PHP's "magic quotes" feature was enabled by default for many years. This practically guaranteed issues with escaped database strings. (Unless the developer spent more time debugging that it would have taken to do it properly in the first place.)
This year, I had to maintain legacy PHP code powering a custom calendar & training-session signup app. Notable horrors I encountered:
- Despite being written by a programmer in the employ of a major Californian company providing security solutions to corporate customers, all passwords were stored in plaintext in the database. The database itself was password-protected by a guessable variation on the company’s name (seriously).
- The ancient register_globals directive was on — not just on, but relied upon. As in, when I moved the code to a server with the directive off (e.g. any modern hosts), all the forms broke. For those who haven’t heard of this, er, “feature,” it means that any variable in the request, be it a cookie name, a GET parameter, or a POST key (that is, the name of an input field on a web form, typically) automatically becomes a global variable in the PHP script set to the provided value. So I could manipulate my DOM, add an <input> field named, say, "is_admin", set its contents to "1", and voilà! $is_admin is now truthy.
- Nothing was ever properly escaped. Not the database, not email headers, not page output.
- And of course, code and HTML were strewn together willy-nilly, with lots of repetition and insane spaghetti-code execution. Let’s just say it was non-trivial to skin all the pages in the app.
I know and you know PHP doesn’t force anyone to commit these sins. But for backwards-compatibility reasons, it still permits them… and I find it hard to believe absolute stinking dangerous messes like this are more common in other modern platforms.