Defining the database
Since you are using the database, you have to do something easier to maintain. Imagine a table called files:
+------------------------------------------+
|nome_arquivo varchar(100) not null unique||
|data_fim date |
|usuario_id varchar (200) |
+------------------------------------------+
And a users table (you will not need a full authentication system, but it can be expanded):
+----------------------------------------------+
|id integer not null primary key auto_increment|
|nome varchar(100) not null unique |
|token varchar (200) not null unique |
+----------------------------------------------+
Mini file access control system
So you do not need to create a login system (in the question it is not clear if you want this (but can be expanded to meet this need)) every time the user sends a new file, it will first generate a token. So we can imagine a simple formmule to do this, let's call user_token.php the file that contains this form:
<form action="gerar_token.php" method="post">
<div>
<label>Nome de usuário</label>
<input type="text" name="nome">
</div>
<div>
<input type="button" value="Obter token">
</div>
</form>
In the file generate_token.php you would have to insert a new record in the users table, where the user name and a token for later access fields would be inserted. Staying like this:
<?php
$usuario_nome = null;
$usuario_token = null;
if(isset($_POST['nome'])){
$nome = $_POST['nome'];
//você pode ler mais sobre uniqid na referencia do php
// em http://php.net/manual/pt_BR/function.uniqid.php
//basicamente ela gerar um identificador unico
//composto por caracteres alphanumericos
$token = md5(uniqid(rand(), true));
$id = criarUsuario($nome, $token);
if($id !== 0){
$conexao = new mysqli('127.0.0.1', 'root', '', 'nome_banco');
//como não tem dados vindo do formulario que precisam ser
//colocados na consulta, não é necessario usuar prepare statement
$resultado = $conexao->query('select nome, token from usuarios
where id = ' . $id);
$usuario = $resultado->fetch_assoc();
$usuario_nome = $usuario['nome'];
$usuario_token = $usuario['toekn'];
}else{
echo 'Aconteceu algum erro ao salvar!';
echo ' Pode ser qualquer coisa, nome de usuario duplicado, etc.';
}
}
/**
@param string $nome nome do usuario vindo do formulario
@param string $token campo aleatorio gerado com a função uniqid()
@return mixed 0 caso o usuario usuario não possa ser salvo
(nome de usuario duplicado, por exemplo), e se o
for salvo com sucesso retornara o id do novo registro
criado (auto_increment), onde id > 0 (maior que zero)
*/
function criarUsuario($nome, $token){
//aqui você deve substituir pelos dados de acesso do seu banco
$conexao = new mysqli('127.0.0.1', 'root', '', 'nome_banco');
//para evitar injeção de sql vamos usar prepare statement
$statement= $conexao->prepare('insert into usuarios (nome, token)
values (?, ?)');
//cada interrogação no instrução acima será representada pelo
//tipo (string, integer, etc) e qual valor irá receber,
//nesse exemplo $nome e $token
$statement->bind_param('ss', $nome, $token);
//e por fim executamos a instrução no banco
$status = $statement->execute();
//se a instrução tiver executado com sucesso, retornamos o id
//do novo registro criado, caso contrario retornamos 0
//(erro ao salvar)
if($status === true){
return $conexao->insert_id;
}
return 0;
}
/******************************************************************
Agora geramos o formulario para enviar arquivos. O formulario poderia
estar em outro arquivo, mas por simplificação vai ficar aqui mesmo.
Tambem mostramos para o usuario: seu nome de usuario e seu token
para que ele possa anota-los, para futuramente usar apenas o token para
enviar arquivos (já que é mais "dificil" de adivinhar)
******************************************************************/
//só mostra o formulario se as variaveis $usuario_nome e $usuario_token
forem diferentes de null, ou seja, foram cadastrados com sucesso
if($usuario_nome === null && $usuario_token === null){
//encerra a execução do script (não mostrando o formulario abaixo)
exit;
}
//caso sejam diferentes de null mostra o formulario
//veja que com o if assima foi possivel "omitir" o else
?>
<div>
<label>
Seu nome de usuario é:<?php echo $usuario_nome; ?>
</label>
<label>
Seu token de acesso é:<?php echo $usuario_token; ?>
</label>
</div>
<form action="salvar_arquivo.php" method="post">
<div>
<label>Insira seu token de acesso</label>
<input type="text" name="token">
</div>
<div>
<label>Escolha um arquivo</label>
<input type="file" name="arquivo">
</div>
<div>
<label>Salvar</label>
<input type="submit" value="Salvar">
</div>
</form>
Most of the functions used in the generate_token.php file are already commented out, but worth mentioning again uniqid , prepare statement , last insert id , fetch assoc (not necessarily in order).
But back to the structure of the above code ( generate_token.php ). In this file a if
was created to verify that the registration form
user had been submitted. The function was then called
cadastrarUsuario()
responsible for inserting a new record in the table
users and return the inserted registry id. The return of this function
was used to make a select in the bank and return, among others, the token
saved in the bank. And finally the form to send files was displayed.
Just one more detail, this form (of sending files) can be placed
in a separate file, when the user has already been "registered". Type this (file send_filename.php):
<form action="salvar_arquivo.php" method="post">
<div>
<label>Insira seu token de acesso</label>
<input type="text" name="token">
</div>
<div>
<label>Escolha um arquivo</label>
<input type="file" name="arquivo">
</div>
<div>
<label>Salvar</label>
<input type="submit" value="Salvar">
</div>
</form>
And now it only lacks the code to save the file sent by the form and list the files of a specific user.
The file save_file.php looks like this:
<?php
if(isset($_POST['token']) && isset($_FILES['arquivo'])){
//pode ser uma pasta fora do public do seu site
//nesse caso esta no mesmo diretorio desse arquivo
$diretorio_arquivos = __DIR__ . '/arquivos';
$token = $_POST['token'];
//cria nome de arquivo unico
$nome_arquivo = $_FILES['name'] . uniqid(rand(), true);
$arquivo_temporario = $_FILES['tmp_name'];
//agora checamos se o tokem existe no banco
if(tokenExiste($token) === true){
$conexao = new mysqli('127.0.0.1', 'root', '', 'nome_banco');
$usuario_id = $conexao("select id from usuarios where token = '" .
$token . "'");
$usuario_id = $usuario_id->fetch_assoc()['id'];
$data_fim = '2018-01-20';
$statement = $conexao->prepare('insert into arquivos
(nome_arquivo, data_fim, usuario_id) values (?, ?, ?)');
$statement->bind_param('ssi', $nome_arquivo, $data_fim,
$usuario_id);
$statement->execute();
//move o arquivo para o diretorio definitivo
move_uploaded_file ( $arquivo_temporario ,
$diretorio_arquivos . '/' . $nome_arquivo );
//da para fazer algumas validações, mas como seria
//necessario fazer rollback no banco, deixo a seu criterio
//implementar
echo 'provavelmene arquivo!';
}
else{
echo 'token invalido! Já fez o cadastro?';
}
}
function tokenExiste($token){
$conexao = new mysqli('127.0.0.1', 'root', '', 'nome_banco');
$statement = $conexao->prepare('select token from usuarios
where token = ?');
$statement->bind_param('s', $token);
$statement->execute();
$statement->store_result();
//token existe
if($statement->num_rows == 1){
return true;
}
return false;
}
The code itself is very explanatory, but it is worth pointing out references to go deeper into move uploaded file , mysqli num rows .
Finally, to list the files of a user, simply join them between the users and files tables. Then in the file list_files.php :
<form method="post">
<input type="text" name="token">
<input type="submit">
</form>
<?php
if(isset($_POST['token'])){
$arquivos = listaArquivos($_POST['token']);
//não existem arquivos ou token invalido, encerra o script
if(count($arquivos) < 1){
echo 'não existem arquivos ou token invalido';
exit;
}
//exibir arquivos em ul
echo '<ul>';
foreach($arquivos as $arquivo){
echo '<li><a href="ver.php?nome=' . $arquivo
. '&token=' . $_POST['token'] . '">' . $arquivo
.'</a></li>';
}
echo '</ul>';
}
function listaArquivos($token){
$conexao = new mysqli('127.0.0.1', 'root', '', 'nome_banco');
$statement = $conexao->prepare('select nome_arquivo from usuarios,
arquivos where token = ? and usuario_id = id');
$statement->bind_param('s', $token);
$statement->execute();
$nome_arquivo = null;
//armazenar o nome de todos os arquivos
$arquivos = [];
$statement->bind_result($nome_arquivo);
//percorre todo o resultset da consulta acima
while ($statement->fetch()) {
$arquivos[] = $nome_arquivo;
}
return $arquivos;
}
?>
And as you always go deeper into bind result , fetch , statement fetch .
Finally, when you click on a link from the list above, you will be redirected to a file called ver.php which will receive as a parameter the name of the file to be displayed and the access token . The ver.php file looks like this:
<?php
$token = $_GET['token'];
$nome_arquivo = $_GET['nome'];
//se existir o token e o nome de arquivo associados a um mesmo usuario
//a função podeAcessar retorna true
if(podeAcessar($nome_arquivo, $token)){
$diretorio_arquivos = __DIR__ . '/arquivos';
//enviando o arquivo para o usuario
$mime = mime_content_type($diretorio_arquivos . '/' . $nome_arquivo);
$tamanho = filesize($diretorio_arquivos . '/' . $nome_arquivo)
header("Content-Type: ". $mime);
header("Content-Length: " . $tamanho);
//retorna o conteudo do arquivo salvo no servidor
//dependendo do tipo de mime ("extensão") o proprio navegador exibira.
//caso não seja compativel com o render oferecido pelo navegador
//será baixado
echo file_get_contents($diretorio_arquivos . '/' . $nome_arquivo);
}else{
echo 'parece que você não pode acessar este arquivo!';
}
function podeAcessar($nome_arquivo, $token){
$conexao = new mysqli('127.0.0.1', 'root', '', 'nome_banco');
$statement = $conexao->prepare('select nome_arquivo from usuarios,
arquivos where token = ? and usuario_id = id and nome_arquivo = ?');
$statement->bind_param('ss', $token, $nome_arquivo);
$statement->execute();
$statement->store_result();
//pode acessar
if($statement->num_rows == 1){
return true;
}
return false;
}
And to deepen the functions used consult
mime content type , filesize , file_get_contents ( All in the php documentation.)
With this you should have a reasonably secure system, since the files will not be in the public directory, because you can create the directory folder a directory above the public folder (server root), for example, doing echo realpath($diretorio_arquivos . '/../pastadearquivos')
. This allows you to access the lastfile folder that is outside the root of the server. In addition it still does to avoid injection attacks (both from sql, as trying to send an arbitrary path).
Note: there may be syntax errors (variables missing letters) since I did not use the interpreter to validate the above codes. But to get a general idea.