Pressione enter para ver os resultados ou esc para cancelar.

Salvando arquivos em formulários no Drupal com segurança

Descubra o porque do arquivo desaparecer e como evitar que o Drupal o apague!

Esses dias passamos por um dificuldade em um projeto aqui na Taller cuja causa e solução gostaria de compartilhar…

O cenário era o seguinte: havia um formulário customizado disponível para o administrador do site com um campo para envio de um arquivo, salvo no diretório de arquivos públicos do Drupal. Um link para este arquivo era disponibilizado para o usuário final, em uma página. Periodicamente, o link do arquivo enviado previamente “sumia” da página onde deveria estar.

Era um problema difícil de reproduzir e fiquei um bom tempo investigando se a variável onde era salva a referência para o arquivo poderia estar sendo sobrescrita ou apagada por algum código.

Depois de finalmente conseguir reproduzir o problema e com as dicas de um colega, foi possível verificar que a variável estava correta, mas o arquivo em si estava sendo removido do sistema de arquivos!

O Drupal se encarrega de limpar, a cada execução da cron, todos os arquivos temporários expirados e não utilizados. Isso é feito da seguinte maneira:

  • Para verificar quais arquivos não são utilizados, é examinada a tabela file_usage do banco de dados.
  • Para verificar quais arquivos estão expirados, é comparada a diferença entre a data atual e a data de criação do arquivo (coluna timestamp da tabela file_managed) com o valor da constante DRUPAL_MAXIMUM_TEMP_FILE_AGE (padrão 21600 segundos, ou seja, 6 horas).

Ou seja, a cada seis horas, quando executada a cron, nosso arquivo era jogado fora…

A solução adotada foi fazer com que o Drupal enxergasse que este arquivo não era temporário e não deveria ser apagado. Isso deve ser feito sempre ao trabalhar com elementos do tipo managed_file em formulários, conforme documentado na API.

Para atingir esse objetivo, no submit do nosso formulário customizado, acrescentamos:

if (!empty($form_state['values'][my_file_field])) {  
    // Load the file.
    $file = file_load($form_state['values'][my_file_field]);
    // Change status to permanent.
    $file->status = FILE_STATUS_PERMANENT;
    // Save.
    file_save($file);
    // Record that this module is using the file (to prevent deletion
    // during cron execution).
    // Modules have no id, but file_usage_add requires this parameter.
    file_usage_add($file, 'my_custom_module', 'module', 0);
  }

Onde my_custom_module é o nome de nosso módulo emy_file_field é o nome do nosso elemento, definido na criação do formulário como:

 $form[my_file_field] = array(
    '#type' => 'managed_file',
    '#choose_file_text' => 'Selecionar arquivo',
    '#change_file_text' => 'Alterar arquivo',
  );

E pronto. Assim, evitamos que o Drupal apague nosso arquivo. Espero que esta breve dica ajude a prevenir problemas parecidos.