Readfile function by dropping PHP session

Asked

Viewed 177 times

4

I had a problem with file downlod, where the session was closed when several download occurred in a short time (less than 1 second) and the same did not occur when the download was slower. (This question can be followed here).

php download file.

<?php
ini_get('safe_mode');
include_once './conf.php'; 
include_once 'class/Conexao.class.php'; 
include_once 'class/Login.class.php'; 

ob_start();
$session_name = 'sec_session_id';

session_start();       
session_regenerate_id();  

//verifica o usuario logado
$log = new Login();

if(!$log->loginCheck() || $log->expired_session()) :
    $site = BASE;
    header("Location:$site");
endif;

if(!isset($_GET['id'])){   header("location: ../erro/5/");}
$id= trim(filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT));
$arq_id = filter_var($id, FILTER_SANITIZE_NUMBER_INT);
$sql = 'SELECT arq_nome, arq_desc FROM arquivo WHERE arq_id = ? LIMIT 1';
$conn = new Conexao();

if($stm = $conn->prepare($sql)):
    $stm->bind_param('i', $arq_id);
    $arq_id = $arq_id;
    $stm->execute();
    $stm->bind_result($arq_nome, $arq_desc);
    $stm->store_result();
    $stm->fetch();
    $dados = array();

    if($stm->num_rows() != 1):
        header("location: ../erro/5/");
    endif;
else:
    echo 'Erro ao selecionar arquivo';
endif;

// Arqui você faz as validações e/ou pega os dados do banco de dados

@set_time_limit(0);

$aquivoNome = $arq_nome; // nome do arquivo que será enviado p/ download
$arquivoLocal = '../../arquivos/XPtCu6bNvxOYBDYilkGL/'. $aquivoNome;

// Verifica se o arquivo não existe
if (!file_exists($arquivoLocal)) {
    // Exiba uma mensagem de erro caso ele não exista
    echo 'nao existe arquivo';
    exit;
}

// Definimos o novo nome do arquivo
$novoNome = $arq_desc;

// Configuramos os headers que serão enviados para o browser
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename="'.$novoNome.'"');
header('Content-Type: application/octet-stream');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($arquivoLocal));
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Expires: 0');

// Envia o arquivo para o cliente
//readfile($arquivoLocal);
header('Connection: close');  
exit;
?>
<script type="text/javascript"> 
window.close();
</script>

php.ini

display_errors = Off
error_reporting = E_ERROR | E_WARNING
magic_quotes_gpc = On
memory_limit = 128M
output_buffering = 4096
post_max_size = 128M
safe_mode = On
safe_mode_exec_dir = /usr/local/www/apache22/batch
safe_mode_gid = On
upload_max_filesize = 128M
include_path = ".:/usr/local/share/phpmailer"

After the event the session was deleted as log below (sessiontime is my session):

[Thu Oct 06 10:14:39.915176 2016] [:error] [pid 3263] [client 10.0.0.2:52344] PHP Notice:  Undefined index: sessiontime in /var/www/html/intranet_academica/adm/index.php on line 106, referer: http://10.0.0.1/intranet_academica/adm/home/6/

NOTE: I had commented the line that checks the user’s session and the above log occurred when I tried to access a page that the login check was active.

After several tests I came to the conclusion that this session drop occurs when I try to download a file without an earlier download (around 57MB) has finished.

My solution was to comment on the line readfile and the problem did not occur anymore, but the file went blank. Does anyone know what the restriction regarding this PHP function linked to session destruction?

  • Searched if reported as BUG? Put the main parts of the code to facilitate.

  • I added my.php download file, if necessary I could post the required files.

  • I didn’t look for if they reported as BUG, in fact I don’t know how to look for it.

  • Did you even consult the log files to check for possible explanations? PHP interpreter log output is active?

  • Yes, the only thing I found was that the session no longer existed. I even put the log in the above question

  • 1

    You are regenerating id: session_regenerate_id(), every upload, this makes the session even drop, as you are replacing the current session with a new one... If you want to regenerate id, do this after completion, not during the process.

  • @Ivanferrer, now that you mention it, I’m pretty sure that’s the problem. And this answers the reason the download only perform logoff when a download was performed before another download finish which generates a new id (session_regenerate_id()), which causes a logoff on the first download. I will continue the tests and you will give a feedback

  • @Ivairferrer, I believe your solution has solved my problem (so far no problems). If possible please post as reply to accept it

Show 3 more comments

1 answer

0

Have you tried using a different strategy to read the file?

$fp = fopen("{$file}", "r");
fpassthru($fp);
fclose($fp);

Maybe it solves some limitation regarding the character overload readfile tries to generate.

  • Another option would be to generate the file and an authorization token in a file, then redirect to the download page with the token in the url and validate if the token is still valid by not letting the session and file merge into the same file.

  • I hadn’t thought about it, cool. If you don’t succeed with the tip above @Ivairferrer I will try this option.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.