Práticas recomendadas para códigos de confirmação por email

Estou criando um site PHP que envolve usuários se inscrevendo e estou pensando sobre práticas recomendadas para códigos de "confirmação por e-mail".

Novos usuários devem confirmar seus endereços de e-mail - eu faço isso gerando um código e enviando-o para o usuário em um e-mail, que ele pode usar para ativar sua conta. Em vez de armazenar essa chave em um banco de dados, estou usando uma pequena solução: o código é o resultado de:

md5("xxxxxxxxx".$username."xxxxxxxxxxx".$timestamp."xxxxxxxxx");

Onde $ timestamp refere-se ao horário de criação do usuário. No geral fiquei bastante satisfeito com isso, mas depois comecei a pensar: isso é seguro o suficiente? E a possibilidade de colisões? E eu também preciso gerar códigos para redefinição de senha, etc. Se eu usasse uma metodologia semelhante, uma colisão poderia resultar em um usuário inadvertidamente redefinir a senha de outro usuário. E isso não é bom.

Então, como você faz essas coisas? Meus pensamentos eram uma tabela do seguinte formato:

codePK (int, a-I), userID (int), type (int), code (varchar 32), date (timestamp)

Onde "tipo" seria 1, 2 ou 3 significando "ativação", "alteração de e-mail" ou "redefinição de senha". Isso é uma boa maneira de fazer isso? Você tem um jeito melhor?

Usando um método semelhante ao acima, eu poderia excluir automaticamente qualquer coisa com mais de dois dias sem usar tarefas cron? Meu host (almostfreespeech.net) não os suporta. Se possível, eu gostaria de evitar ter um cron-job em um host externo, o qual é um script que apaga as coisas, já que isso é bagunçado = P.

Obrigado!
Mala

Atualizar:
Para esclarecer: eu percebi que a única maneira segura e segura de realizar essa tarefa é usando um banco de dados, que é o que a função original estava tentando evitar. Minha pergunta é sobre como a tabela (ou tabelas?) Deve ser estruturada. Alguém sugeriu que eu acabe com o codePK e apenas torne o código um PK. Então, em suma, minha pergunta é: é isso que você faz?

questionAnswers(5)

yourAnswerToTheQuestion