Há duas coisas que você está perguntando:
- Como impedir o acesso externo a um (conjunto de) arquivo (s)
- Como autenticar um usuário e permitir o acesso do PHP (e do usuário) ao (s) arquivo (s)
Espero que isso esclareça o papel que cada componente desempenha - embora possa ser um pouco excessivo.
Impedir acesso externo a arquivos:
Esta parte é feita pelo seu servidor web - neste caso nginx.
Em sua configuração nginx (seu bloco de servidor), você especifica um caminho root
. Por padrão, todos os arquivos sob esse caminho raiz estão diretamente acessíveis.
Por exemplo, considere o seguinte (o domínio é 'exemplo.com')
root /var/www/example.com/public_html
Se você tiver um arquivo, uploaded_file.zip
, ele estará acessível das seguintes maneiras:
- Localização: /var/www/example.com/public_html/uploaded_file.zip - acessível via example.com/uploaded_file.zip
- Localização: /var/www/example.com/uploaded_file.zip - não acessível (mesmo usando example.com /../ uploaded_file.zip)
Em essência, um arquivo acima da raiz do documento não será acessível através de um navegador, entretanto, a maioria das configurações do PHP permitirá que seu código leia o arquivo e entregue-o (restrições a isso são geralmente um resultado de open_basedir
)
Em alguns cenários, pode ser preferível ter seus arquivos sob a raiz do documento. Para fazer isso e ainda impedir o acesso externo (direto), você usará a diretiva internal
. Por exemplo:
localização / uploads { interno; }
Agora, todos os arquivos colocados em /var/www/example.com/public_html/uploads são acessíveis internamente (ou seja, não podem ser acessados por meio de um navegador, mas podem ser acessados por seus scripts PHP). Se desejar, você também pode configurar um alias no local / uploads, para que outro caminho também possa ser usado para fazer referência a ele.
Neste ponto, seus arquivos não estão diretamente acessíveis, mas seus scripts ainda podem atendê-los.
Autenticação do usuário e PHP:
Considere o seguinte design básico: Um usuário pode acessar um arquivo diretamente ou acessar a página de login. Se eles tentarem acessar um arquivo diretamente e estiverem logados (e tiverem permissão), o arquivo será baixado, caso contrário, eles serão exibidos na tela de login. Para carregar um arquivo, um usuário precisa estar logado.
Digamos que seu script de download (a página que entregará o arquivo ao usuário) seja chamado de 'download.php'. Um URL típico pode ser example.com/download.php?file=uploaded_file.zip. É bem provável que você não queira que seus URLs incluam o nome do arquivo php. Para evitar isso, você pode configurar uma regra de reescrita em sua configuração nginx que apontará outro local (digamos / arquivos) em seu script. Adicione à sua configuração do nginx:
rewrite ^/files/(.*) /download.php?file=$1 last;
(O que equivale a mudar o caminho requisitado de qualquer requisição começando com / files, e capturar tudo após o / e passá-lo como um parâmetro de consulta para o seu arquivo php);
Agora, seu arquivo pode ser acessado via: example.com/files/uploaded_file.zip (que redireciona internamente para o seu script php).
Seu arquivo PHP (download.php) agora faz o seguinte:
- Iniciar a sessão
- Se o usuário estiver logado, prossiga, caso contrário, redirecione para uma página de login, passando o arquivo de destino como parte da string de consulta
- Consulte seu banco de dados (por exemplo, MySQL) para ver se o usuário pode acessar esse arquivo
- Se o usuário tiver permissão, prossiga, caso contrário, redirecione para uma página de erro
-
Produza os cabeçalhos necessários (Content-Type, Content-Disposition, etc) e defina:
X-Accel-Redirect: /uploads/uploaded_file.zip;
Note que você pode fazer o download real do PHP (por exemplo, usando readfile
) - é apenas um pouco mais eficiente, especialmente para arquivos grandes) para fazer isso via nginx. Além disso, apesar do usuário aparecer para acessar o arquivo diretamente, internamente, ele está passando pelo PHP, que está autenticando-os antes de permitir que eles continuem.
URL -> nginx (redirect to PHP) -> PHP (authenticate) -> nginx (serve file)
No lado do envio das coisas, você vai move_uploaded_file
para /var/www/example.com/public_html/uploads (que é protegido pela diretiva 'interna' e, portanto, os arquivos não podem ser acessados diretamente), e salvar permissões no seu banco de dados.