What is best practise for salting and multiple-hashing of passwords? I have been presented with some custom PHP code for salting passwords and applying multiple rounds of hashing.

It looks reasonable, but I fear home-grown crypto.

Is there an existing password salting and multiple hashing algorithm which I could use instead of code from a non-cryptographer.

The algorithm needs to accept a password, a salt and the number of rounds.

I've found bcrypt, which looks appropriate, but I'm concerned that it's old.
Current best practice does include bcrypt, which is the same as PHP's built in password_hash() function. Future best practice will probably be Argon2.

Other widely used secure KDF options include PBKDF2 with SHA512 or SHA256 as the hash function, and scrypt. scrypt and bcrypt differ from PBKDF2 in that they can use large amounts of memory, and thus resist cracking on commodity hardware better, which has more processing power than memory in the context of hash brute forcing.

bcrypt and PBKDF2 do have a specific issue, which is that a large password can cause the algorithm do behave in a way one would not expect. In bcrypt, there is a hard limit on input text, and a long password is simply truncated. In PBKDF2, the password is used as a direct input to HMAC, and if it is too large, the hash function must process the data more than once. My fix is to simply hash the password once with SHA512 before sending it to the KDF, as that makes the password input 64 bytes, which is within the bcrypt limit, and needs only a single hash with PBKDF2-SHA512.

Storage in the database is also an issue. Best practice is to use either the Modular Crypt Format or the PHC String Format. The trend is to use the PHC format over MCF as it is still based on MCF, but more flexible, and with more specific rules. PHC format with parameters allows forwards/cross compatibility and easy migration.

An example PHC format string:

$bpmhash_sha512$i=5,l=48$caaaaaaaaaaaaaaaaaaaaaaaaaaaaaab$HvrCpcKm209ikRst7gpsWbh1p5QyiA33R6iovxo0da6CX+lU1wKw0SserPtb6U3O

Where :
algorithm = bpmhash_sha512 (pbkdf2 with 1 round prehash)
i = the round count as 5
l = the output in bytes as 48
salt = caaaaaaaaaaaaaaaaaaaaaaaaaaaaaab
hash = HvrCpcKm209ikRst7gpsWbh1p5QyiA33R6iovxo0da6CX+lU1wKw0SserPtb6U3O