<?php
//
Class Sessao_Php {
   Public $nEsperaSeg;
   Private $Salvar_Path;
   Private $nHandleArq;
   Private $nTamanhoArq;
   Private $sNomeArq;
   Private $sNomeArq_Lock;
   Private $Id_Temp;
   Private $bTravado;
   //
   Function Monta_Nome($s_Id) {
      $this->sNomeArq      = $this->Salvar_Path."/sessao_ec_".$s_Id.".tmp";
      $this->sNomeArq_Lock = $this->Salvar_Path."/sessao_ec_".$s_Id.".lck";
   }
   //
   Function AbrirArq( $bGravacao ) {
	  If ( $this->nHandleArq==0 ) {
	     //
         If ( $bGravacao ) {
		    If ( ! $this->bTravado ) {
		       If ( ! $this->Lock_Arq(1) ) { Return False; }
			}
	        $nTempo = TIME();
            While ( ! ($nHandle = @FOPEN($this->sNomeArq, "w") )) {
		       If ( ($nTempo+$this->nEsperaSeg) < TIME() ) {
				  $this->bTravado = False;
                  $this->Lock_Arq(0);
		          //ERROR_LOG("Sessao_Php:File Write -> Error open file", 0);
		          ERROR_LOG("Sessao_Php( AbrirArq ) : ERRO - O tempo expirou para abrir o arquivo de sessão no modo gravação. Erro no FOPEN().", 0);
		          Return False;
		       }
		    }
			$this->bTravado = True;
	     //
	     } Else {
	        If ( FILE_EXISTS($this->sNomeArq) ) {
		       If ( ! $this->bTravado ) {
		          If ( ! $this->Lock_Arq(1) ) { Return False; }
			   }
	           $nTempo = TIME();
               While ( ! ($nHandle = @FOPEN($this->sNomeArq, "r") )) {
		          If ( ($nTempo+$this->nEsperaSeg) < TIME() ) {
				     $this->bTravado = False;
                     $this->Lock_Arq(0);
		             //ERROR_LOG("Sessao_Php:File Read-> Error open file", 0);
		             ERROR_LOG("Sessao_Php( AbrirArq ) : ERRO - O tempo expirou para abrir o arquivo de sessão no modo leitura. Erro no FOPEN().", 0);
		             Return False;
		          }
		       }
		       $this->nTamanhoArq = FILESIZE($this->sNomeArq);
			   $this->bTravado = True;
		    } Else {
		       Return False;
		    }
	     }
         $this->nHandleArq = $nHandle;
	  }
	  //
      Return True;
   }
   //
   Function FechaArq($bDestravar=True) {
      If ( $this->nHandleArq>0 ) {
	     FCLOSE($this->nHandleArq);
		 If ( $bDestravar ) {
		    $this->Lock_Arq(0);
			$this->bTravado = False;
	     }
		 $this->nHandleArq = 0;
		 $this->nTamanhoArq = 0;
		 Return True;
	  }
      Return False;
   }
   //
   Function Lock_Arq($nOpc=0) {   // 0=Destravar, 1=Travar, 2=Verificar (True = Destravado, False = Travado )
      If ( $nOpc==0 ) {
	     If ( FILE_EXISTS($this->sNomeArq_Lock) ) {
		    UNLINK($this->sNomeArq_Lock);
		 } Else {
		    Return False;
		 }
		 Return True;
      } ElseIf ( $nOpc==1 ) {
         $nTempo = TIME();
         While ( FILE_EXISTS($this->sNomeArq_Lock) ) {
            If ( ($nTempo+$this->nEsperaSeg) < TIME() ) {
                //ERROR_LOG("Sessao_Php:File Write -> Error locked file", 0);
		        ERROR_LOG("Sessao_Php( Lock_Arq ) : ERRO - O tempo de espera para travar a sessão já travada expirou.", 0);
                Return False;
            }
			USLEEP(100000);    // Espera 1 segundo
         }
		 $nHandle = @FOPEN($this->sNomeArq_Lock, "w");
	     FWRITE($nHandle, $this->Id_Temp);
		 FCLOSE($nHandle);
		 Return True;
      } ElseIf ( $nOpc==2 ) {
		 Return ( ! FILE_EXISTS($this->sNomeArq_Lock) );
	  }
	  Return False;
   }
   //
   Function open($save_path, $session_name) {
      $this->Id_Temp = $this->_GeraChave(6);
      $this->Salvar_Path = $save_path;
      $this->nHandleArq = 0;
      $this->nTamanhoArq = 0;
      Return(True);
   }
   //
   Function close()  {
      $this->FechaArq();
      Return(true);
   }
   //
   Function read($id) {
      $this->Monta_Nome($id);
      $this->FechaArq(False);
      If ( ! $this->AbrirArq(False) ) { Return ""; }
	  If ( $this->nTamanhoArq==0 ) {
	     //ERROR_LOG("Sessao_Php:File -> Alert, file zero size", 0);
         ERROR_LOG("Sessao_Php( read ) : ALERTA - O tamanho do arquivo de sessão indica que está vazio.", 0);
	  }
	  REWIND($this->nHandleArq);
      $sDados = FREAD($this->nHandleArq, $this->nTamanhoArq);
	  If ( EMPTY($sDados) ) {
	     //ERROR_LOG("Sessao_Php:File -> Alert, empty file", 0);
         ERROR_LOG("Sessao_Php( read ) : ALERTA - O arquivo de sessão retornou uma leitura vazia.", 0);
	  }
      //$this->FechaArq();
      Return($sDados);
   }
   //
   Function write($id, $sDados) {
      $this->Monta_Nome($id);
      $this->FechaArq(False);
      If ( ! $this->AbrirArq(True) ) { Return False; }
	  If ( EMPTY($sDados) ) {
	     //ERROR_LOG("Sessao_Php:File -> Alert, empty write", 0);
         ERROR_LOG("Sessao_Php( write ) : ALERTA - Não há dados a serem gravados no arquivo de sessão.", 0);
	  } Else {
	     $this->nTamanhoArq = FWRITE($this->nHandleArq, $sDados);
	     If ( $this->nTamanhoArq==0 ) {
	        //ERROR_LOG("Sessao_Php:File -> Error, no write", 0);
            ERROR_LOG("Sessao_Php( write ) : ERRO - Não foi possível gravar os dados de destino no arquivo de sessão.", 0);
	     }
	  }
      //$this->FechaArq();
      Return( True );
   }
   //
   Function destroy($id) {
      $this->Monta_Nome($id);
      $this->FechaArq();
      Return( UNLINK($this->sNomeArq) );
   }
   //
   Function gc($maxlifetime) {
     return true;
   }
   //
   Function _GeraChave($nCompChave=30) {     // Gera chave aleatório em string
     $CaracteresAceitos = 'abcdefghijlkmnopqurtvxzwABCDEFGHIJLKMNOPQURTVXZW0123456789';
     $TamanhoAcMax = strlen($CaracteresAceitos)-1;
     $strChaveGerada = '';
     for($i=0; $i < $nCompChave; $i++) {
       $strChaveGerada .= $CaracteresAceitos{mt_rand(0, $TamanhoAcMax)};
     }
     Return $strChaveGerada;
   }
}
//
$Sessao_Php_WP = New Sessao_Php();
$Sessao_Php_WP->nEsperaSeg = 25;
SESSION_SET_SAVE_HANDLER(
  ARRAY( &$Sessao_Php_WP,"open"   ),
  ARRAY( &$Sessao_Php_WP,"close"  ),
  ARRAY( &$Sessao_Php_WP,"read"   ),
  ARRAY( &$Sessao_Php_WP,"write"  ),
  ARRAY( &$Sessao_Php_WP,"destroy"),
  ARRAY( &$Sessao_Php_WP,"gc"     )
);
//
?>