Eu tenho um sistema (aplicativo baseado na Web) que extrai anexos de arquivos de um sistema de terceiros via SOAP. Estes, por sua vez, são criados em nosso sistema como arquivos em um diretório.
Quando um usuário do sistema (autenticado por meio do ldap) faz um pedido ao meu aplicativo para recuperar um destes anexos:
1. I request it via soap
2. Process the response to build the file on our system
3. Redirect user to the location so they can download the file.
Primeiro, essa é uma boa abordagem?
Existe uma maneira melhor de servir arquivos que não residirão no servidor muito após o download do anexo (o trabalho cron limpará o diretório de vez em quando)?
Em segundo lugar, existe uma maneira de eu servir arquivos através do apache sem armazená-los na raiz da web?
Em terceiro lugar, como impor permissões nesses arquivos para que nenhum usuário possa baixar qualquer anexo?
Nossa instalação:
linux
apache
php - soap libraries for communication
seperate LDAP for authentication
3rd party soap server (where attachments come from)
EDIT: O código para veicular o anexo, caso alguém esteja curioso.
<?php
ini_set('display_errors',1);
error_reporting(E_ALL|E_STRICT);
//require global definitions
require_once("includes/globals.php");
//validate the user before continuing
isValidUser();
$subTitle = "Attachment";
$attachmentPath = "/var/www/html/DEVELOPMENT/serviceNow/selfService/uploads/";
if(isset($_GET['id']) and !empty($_GET['id'])){
//first lookup attachment meta information
$a = new Attachment();
$attachment = $a->get($_GET['id']);
//filename will be original file name with user name.n prepended
$fileName = $attachmentPath.$_SESSION['nameN'].'-'.$attachment->file_name;
//instantiate new attachmentDownload and query for attachment chunks
$a = new AttachmentDownload();
$chunks= $a->getRecords(array('sys_attachment'=>$_GET['id'], '__order_by'=>'position'));
$fh = fopen($fileName.'.gz','w');
// read and base64 encode file contents
foreach($chunks as $chunk){
fwrite($fh, base64_decode($chunk->data));
}
fclose($fh);
//open up filename for writing
$fh = fopen($fileName,'w');
//open up filename.gz for extraction
$zd = gzopen($fileName.'.gz', "r");
//iterate over file and write contents
while (!feof($zd)) {
fwrite($fh, gzread($zd, 60*57));
}
fclose($fh);
gzclose($zd);
unlink($fileName.'.gz');
$info = pathinfo($fileName);
header('Content-Description: File Transfer');
header('Content-Type: '.Mimetypes::get($info['extension']));
header('Content-Disposition: attachment; filename=' . basename($fileName));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($fileName));
ob_clean();
flush();
readfile($fileName);
exit();
}else{
header("location: ".$links['status']."?".urlencode("item=incident&action=view&status=-1&place=".$links['home']));
}
?>
Respostas:
Parece bom para mim. Apenas certifique-se de autenticar o usuário antes de passar por tudo isso.
Coloque os arquivos fora da raiz da web. Em seguida, usando PHP, passe o arquivo por um script. Dessa forma, ninguém pode vincular o arquivo diretamente e ignorar seus controles. (Naturalmente, verifique se o script que faz isso somente após verificar o usuário tem permissão para recuperar esse arquivo).
Exemplo de PHP:
Faça com que os usuários efetuem login para recuperar seus arquivos. Em seguida, você pode definir uma variável de sessão identificando-as como tendo permissão para fazer o download. Verifique se os scripts os autenticam em todas as páginas deste processo.
fonte