@lolwtf said:
glibc has a potential excuse - C doesn't support such nice things as optional/variable parameters, and they were hacking this functionality into an existing API that they couldn't really go about changing. PHP's problem is that things are generally just direct mappings to the original API, rather than using the language's features to handle such insanity internally.
I can see wanting to keep compatibility with code ported from C, but that doesn't mean you can't add a crypt_sane() or something that handles the API better.
glibc's best excuse is that it was trying to hack something better than DES into the existing /etc/shadow format (which, having borrowed /etc/passwd's hashing mechanism, was already a few years behind the curve). Shadow passwords require the salt be stored with the password, and storing the hash algorithm in the string lets you mix algorithms within the same shadow file. In addition, most implementations will strip off any parts of the salt that don't make sense when doing the evaluation (e.g. "QWERTYUIO" as salt becomes "QW" and "$1$QWERTYUI$OPASDFGHJKLZXCVBNM" becomes "$1$QWERTYUI$"). So, legacy code evaluating strcmp(crypt(password,hash),hash) mostly just works, which is quite helpful in this exact use case.
That said, no, none of the above makes it a good general-purpose solution for storing passwords. You could argue that the real WTF is that PHP implemented a function that's only really useful if you have read access to /etc/shadow, but I might then argue that the real WTF is any assumption that the PHP language was truly was "designed" from the get-go.
(Others have suggested useful solutions like mcrypt; I'm just defending libc's honor, here.)