Como evitar condições de corrida ao escrever / ler variáveis de sessão do joomla de um script php externo?

9

PERGUNTAS

  • A perda intermitente de dados da sessão provavelmente é devido a uma condição de corrida? Se não, qual é o problema provável?
  • Como posso evitar condições de corrida ao escrever / ler joomla variáveis de sessão de um script php externo?

DETALHES

Estou usando

  • Joomla 2.5
  • PHP 5.4.3
  • apache 2.2.22
  • mysql 5.5.24
  • wampserver 2 no host local.
  • Meu script é externo ao Joomla.
  • (cometchat versão 3.0.1)

O script está usando solicitações de ajax assíncronas para obter e definir variáveis do joomla várias vezes. Os dados que estou armazenando na sessão são uma matriz. Intermitentemente, alguns dos dados da matriz desaparecem. Parece acontecer de forma muito mais consistente quando o usuário efetua login e usa o script.

Para ser honesto, não sei ao certo qual é o problema, mas estou começando a pensar que meu código está sofrendo de uma condição de corrida. Eu acho que o Joomla pode estar tentando ler as informações da sessão antes de terminar de ser escrita ou ela não está sendo configurada. A informação que falta parece ser escolhida aleatoriamente e a perda de dados ocorre de forma intermitente.

SCRIPT1

O Script 1 está usando uma solicitação de ajax assíncrona para obter / definir as variáveis de sessão do Joomla. Isso será chamado várias vezes. Devido ao design, o script 1 não pode ser chamado novamente até que a resposta do ajax seja bem-sucedida.

$.ajax(
            {   cache:false,
                url: 'script2.php',
                data: { 'change': change},              
                dataType: 'json',               
                success: function(data) 
                {
                    //do something
                }
            });

Esta é uma idéia aproximada do código que estou usando no script 2 para acessar o Joomla e obter / definir dados da sessão.

SCRIPT2

<?php
//some code omitted for brevity

$app = &JFactory::getApplication('site');/
$app->initialise();                     

$nottimedout=false;
$session = JFactory::getSession();
$jquizstart = date( 'Y-m-d H:i:s', time() );    //<<-- time of access       
$nottimedout = $session->has('jtimedout');

if ($nottimedout==true)
{
    $jqid = $session->get('jqid');                //<<-- get array from session
    if (isset($_GET['change'])) 
    { 
        $qnumber=$_GET['change'];   
        $firephp->log($qnumber, 'qnumber');
        $jqid[$qnumber][3]=$jquizstart;     //<<--  add time of access to array
        $firephp->log($jqid[$qnumber][3], '$jqid[$qnumber][3]');
        $session->set('jqid', $jqid);       //<<-- store array in Joomla with updated data
    } 
    else
    {
        $firephp->log('CHANGE NOT SET');
    }

    echo json_encode(
                      array("nottimedout" => $nottimedout) 
                    );                  
}
else 
{
    //Do something  
}
?>

TESTE PARA CONDIÇÕES DE CORRIDA

Eu achei que os dados podem estar sendo substituídos, então fiz um teste rápido usando o código abaixo. Cada vez que eu atualizo o array de sessão eu crio uma nova variável de sessão apenas com os dados atualizados.

$qnum[$qnumber]=$jquizstart;
$session->set('var'.$qnumber, $qnum);

Em outro script, quando o site concluiu a atualização, verifiquei cada uma das sessões individuais para ver se elas foram definidas.

//Test for race condition in Joomla session

        for ($counter=0; $counter<=$totalnumber-1; $counter++)
        {
            $racecondition=$session->get('var'.$counter);               
            $firephp->log($racecondition, 'var'.$counter.'=');
        }

RESULTADOS DO TESTE

As informações de matriz ausentes do jqid também estavam ausentes da sessão individual correspondente (a sessão com apenas os dados atualizados), portanto, parece que não é um problema de os dados serem sobrescritos. Não tenho certeza se isso refuta uma condição de corrida.

Qualquer sugestão sobre o que você acha que pode estar acontecendo e como consertar isso seria muito bem-vinda.

EDITAR

Até mesmo respostas generalizadas sobre como evitar condições de corrida no Joomla são bem-vindas. Obrigado

EDIT2

Estou começando a me perguntar se não é um problema com o php5.4 e o Joomla. Ouvi dizer que eles não tocam bem juntos e não me lembro de ter esse problema antes de atualizar do php5.3. Eu posso estar errado.

EDIT3

Eu estou no fim do juízo. Eu instalei o site em um servidor diferente com o PHP 5.3.10. Eu tentei dez ou mais vezes como um usuário não logado. Não houve perda de dados. Então eu entrei no Joomla e os dados foram perdidos quase toda vez que eu acessei a página. Se eu não tivesse que usar as sessões do Joomla! GRRRrrrrr

EDIT4

Ficando desesperado agora e apenas tentando qualquer coisa. O JRequest não funcionou, embora eu deva usá-lo de qualquer maneira.

Como o problema ocorre com mais frequência quando efetuado login, concluí que deve ser porque há muito mais conteúdo armazenado na sessão do que quando o usuário é um convidado. O Jqid é um array grande, então ao invés de atualizá-lo o tempo todo, eu tentei criar vários arrays menores e atualizar cada um quando apropriado. Não teve absolutamente nenhum efeito. Mais uma vez, eu provavelmente deveria estar fazendo isso de qualquer maneira.

EDIT5B

Ao tentar encontrar uma solução improvisada, tentei testar se a sessão foi atualizada com sucesso ou não (isso foi feito no mesmo script que atualizou a sessão).

Aqui está o código que usei para verificar o jstart.

//jstart updated
$session->close('jstart');
$try_again_session = JFactory::getSession();
$newjstart=$try_again_session->get('jstart');
$firephp->log($newjstart[$qnumber], 'confirm_jstart_set=');

A coisa interessante que descobri foi que, o jstart continha as informações atualizadas durante a verificação, mas na conclusão estava faltando. Eu não tenho certeza do que isso significa, mas eu acho que se nós tratássemos JFactory::getSession() como uma variável então a variável foi atualizada apenas para este script (tipo como uma variável local?), O valor do banco de dados para JFactory::getSession() motivo não foi gravado no banco de dados. Assim, mais tarde, quando esse script foi acionado novamente, ele recuperou o valor antigo de JFactory::getSession() que foi salvo no banco de dados.

Ainda não tenho ideia do que está fazendo com que a sessão não seja gravada no banco de dados.

    
por moomoochoo 28.12.2012 в 02:17
fonte

2 respostas

2

Finalmente, parece que encontrei uma solução!

Por acaso, verifiquei os logs de erros em apache_error.log (wamp / logs / apache_error.log). Havia uma tonelada de erros relacionados à sessão, como

PHP Warning:  session_start(): Cannot send session cache limiter - headers already sent (output started at Z:\libraries\joomla\session\session.php:96) in Z:\libraries\joomla\session\session.php on line 532, referer: http://localhost/cq
PHP Warning:  Cannot modify header information - headers already sent by (output started at Z:\libraries\joomla\session\session.php:96) in Z:\cometchat\cometchatcss.php on line 68, referer: http://localhost/cq
PHP Warning:  session_destroy(): Session object destruction failed in Z:\libraries\joomla\session\session.php on line 96, referer: http://localhost/cq

Depois de desligar o cometchat e reiniciar o servidor, descobri que a perda de dados da sessão intermitente parecia parar. Após a mudança, não apareceram mais erros em apache_error.log

Como o problema é intermitente, não estou 100% certo de que está resolvido, mas estou confiante de que escrevi isso como a solução. Eu estava usando

versão 3.0.1 do cometchat

Vou continuar testando. Se a solução persistir, tentarei uma versão atualizada do cometchat e postarei os resultados.

UPDATE: Parece estar relacionado ao cometchat. Eu instalei a última versão 4.6.0, mas a perda de sessão ainda está ocorrendo. Eu posso contornar isso excluindo o cometchat nas páginas que contêm meu script.

INFORMAÇÕES ÚTEIS:  Apenas no caso de alguém encontrar-se lutando com a sessão do Joomla - eu encontrei este site bastante útil link

Especificamente

$session->getId();
$session->get('session.counter');
$session->isNew();
$session->getName();
$session->getState();
$session->getExpire();
    
por moomoochoo 28.12.2012 / 12:00
fonte
3

Embora eu não tenha encontrado uma solução para o problema, encontrei um trabalho por aí. Não é bom, mas funciona. Sempre que a variável de sessão é atualizada, armazene as informações em um cookie como um backup. Posteriormente no script, verifique se há informações ausentes e atualize o cookie conforme necessário.

Eu prefiro não fazer assim, mas não parece que eu tenha escolha.

    
por TryHarder 04.11.2012 / 07:59
fonte