Defining the database
Since you are using a database, you can 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 table users (a full authentication system will not be required, but 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
To avoid creating a login system (in the question it is not clear if you want it (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 form to do this, let’s call it usuario_token.php the file containing 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 archive gerar_token.php would have to insert a new record in the table users, where the user name and a token for later access fields would be inserted. Thus:
<?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/en/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 archive gerar_token.php are already commented, but worth quoting again uniqid, prepare statement, last Insert id, fetch Assoc (not necessarily in order).
But back to the code structure above (gerar_token.php). In this file was created a if
to check whether the registration form
user had been submitted. Then a call was made to the function
cadastrarUsuario()
responsible for entering a new record in the table
users and return the id of the inserted record. The return of this function
was used to make a select in the bank and return, among others, the token
saved in the database. And finally the form to send files was displayed.
Just one more detail, this form (to send files) can be placed
in a separate file, when the user has already been "registered". Type this (.php file.):
<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 only missing the code to save the file sent by the form and list the files of a specific user.
The archive salvar_file.php gets 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 highlighting references to deepen in move uploaded file, mysqli in a Rows.
And finally to list a user’s files just make a Join between the tables users and files. So in the file list.php files:
<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 always deepens into bind result, fetch, statement fetch.
Finally, when you click on a link from the above list, you will be redirected to a file called see php. you will receive as parameter the name of the file to be displayed and the access token. The file see php. gets 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 documentation of php).
With this you should have a reasonably secure system, since the files will not be in the public directory, as you can create the file folder a directory above the public folder (server root), for example, doing echo realpath($diretorio_arquivos . '/../pastadearquivos')
. This allows you to access the folder grazing that is out of the server’s root. Also, to prevent injection attacks (both of sql, such as trying to send an arbitrary path).
Note: There may be syntax errors (variables missing letters) as I did not use the interpreter to validate the above codes. But you can get a general idea.
Anderson recommend you to do the tour to understand how the community works, first try to do something, then ask the question by exposing your question and or problem.
– user81560
Okay, let’s consider as settled, I’ll start the development and post again. Thank you.
– Anderson