<?php
// GIJOE's Ticket Class (based on Marijuana's Oreteki XOOPS)
// nobunobu's suggestions are applied

if( ! class_exists( 'XoopsGTicket' ) ) {

class XoopsGTicket {

	var $_errors = array() ;
	var $_latest_token = '' ;

	// render form as plain html
	function getTicketHtml( $salt = '' , $timeout = 1800 , $area = '' )
	{
		return '<input type="hidden" name="XOOPS_G_TICKET" value="'.$this->issue( $salt , $timeout , $area ).'" />' ;
	}

	// returns an object of XoopsFormHidden including theh ticket
	function getTicketXoopsForm( $salt = '' , $timeout = 1800 , $area = '' )
	{
		return new XoopsFormHidden( 'XOOPS_G_TICKET' , $this->issue( $salt , $timeout , $area ) ) ;
	}

	// returns an array for xoops_confirm() ;
	function getTicketArray( $salt = '' , $timeout = 1800 , $area = '' )
	{
		return array( 'XOOPS_G_TICKET' => $this->issue( $salt , $timeout , $area ) ) ;
	}

	// return GET parameter string.
	function getTicketParamString( $salt = '' , $noamp = false , $timeout=1800 , $area = '' )
	{
	    return ( $noamp ? '' : '&amp;' ) . 'XOOPS_G_TICKET=' . $this->issue( $salt, $timeout , $area ) ;
	}

	// issue a ticket
	function issue( $salt = '' , $timeout = 1800 , $area = '' )
	{
		global $xoopsModule ;
	
		// create a token
		list( $usec , $sec ) = explode( " " , microtime() ) ;
		$appendix_salt = empty( $_SERVER['PATH'] ) ? XOOPS_DB_NAME : $_SERVER['PATH'] ;
		$token = crypt( $salt . $usec . $appendix_salt . $sec ) ;
		$this->_latest_token = $token ;

		if( empty( $_SESSION['XOOPS_G_STUBS'] ) ) $_SESSION['XOOPS_G_STUBS'] = array() ;

		// limit max stubs 10
		if( sizeof( $_SESSION['XOOPS_G_STUBS'] ) > 10 ) {
			$_SESSION['XOOPS_G_STUBS'] = array_slice( $_SESSION['XOOPS_G_STUBS'] , -10 ) ;
		}

		// record referer if browser send it
		$referer = empty( $_SERVER['HTTP_REFERER'] ) ? '' : $_SERVER['REQUEST_URI'] ;

		// area as module's dirname
		if( ! $area && is_object( @$xoopsModule ) ) {
			$area = $xoopsModule->getVar('dirname') ;
		}

		// store stub
		$_SESSION['XOOPS_G_STUBS'][] = array(
			'expire' => time() + $timeout ,
			'referer' => $referer ,
			'area' => $area ,
			'token' => $token
		) ;

		// paid md5ed token as a ticket
		return md5( $token . XOOPS_DB_PREFIX ) ;
	}

	// check a ticket
	function check( $post = true , $area = '' )
	{
		global $xoopsModule ;

		$this->_errors = array() ;

		// CHECK: stubs are not stored in session
		if( empty( $_SESSION['XOOPS_G_STUBS'] ) || ! is_array($_SESSION['XOOPS_G_STUBS'])) {
			$this->clear() ;
			$this->_errors[] = 'Invalid Session' ;
			return false ;
		}

		// get key&val of the ticket from a user's query
		if( $post ) {
			$ticket = empty( $_POST['XOOPS_G_TICKET'] ) ? '' : $_POST['XOOPS_G_TICKET'] ;
		} else {
			$ticket = empty( $_GET['XOOPS_G_TICKET'] ) ? '' : $_GET['XOOPS_G_TICKET'] ;
		}

		// CHECK: no tickets found
		if( empty( $ticket ) ) {
			$this->clear() ;
			$this->_errors[] = 'Irregular post found' ;
			return false ;
		}

		// gargage collection & find a right stub
		$stubs_tmp = $_SESSION['XOOPS_G_STUBS'] ;
		$_SESSION['XOOPS_G_STUBS'] = array() ;
		foreach( $stubs_tmp as $stub ) {
			// default lifetime 30min
			if( $stub['expire'] >= time() ) {
				if( md5( $stub['token'] . XOOPS_DB_PREFIX ) === $ticket ) {
					$found_stub = $stub ;
				} else {
					// store the other valid stubs into session
					$_SESSION['XOOPS_G_STUBS'][] = $stub ;
				}
			} else {
				if( md5( $stub['token'] . XOOPS_DB_PREFIX ) === $ticket ) {
					// not CSRF but Time-Out
					$timeout_flag = true ;
				}
			}
		}

		// CHECK: the right stub found or not
		if( empty( $found_stub ) ) {
			$this->clear() ;
			if( empty( $timeout_flag ) ) $this->_errors[] = 'Invalid Session' ;
			else $this->_errors[] = 'Time out' ;
			return false ;
		}

		// set area if necessary
		// area as module's dirname
		if( ! $area && is_object( @$xoopsModule ) ) {
			$area = $xoopsModule->getVar('dirname') ;
		}

		// check area or referer
		if( @$found_stub['area'] == $area ) $area_check = true ;
		if( ! empty( $found_stub['referer'] ) && strstr( @$_SERVER['HTTP_REFERER'] , $found_stub['referer'] ) ) $referer_check = true ;

		// if( empty( $area_check ) || empty( $referer_check ) ) { // restrict
		if( empty( $area_check ) && empty( $referer_check ) ) { // loose
			$this->clear() ;
			$this->_errors[] = 'Invalid area or referer' ;
			return false ;
		}

		// all green
		return true;
	}


	// clear all stubs
	function clear()
	{
		$_SESSION['XOOPS_G_STUBS'] = array() ;
	}


	// Ticket Using
	function using()
	{
		if( ! empty( $_SESSION['XOOPS_G_STUBS'] ) ) {
			return true;
		} else {
			return false;
		}
	}


	// return errors
	function getErrors( $ashtml = true )
	{
		if( $ashtml ) {
			$ret = '' ;
			foreach( $this->_errors as $msg ) {
				$ret .= "$msg<br />\n" ;
			}
		} else {
			$ret = $this->_errors ;
		}
		return $ret ;
	}

// end of class
}

// create a instance in global scope
$GLOBALS['xoopsGTicket'] = new XoopsGTicket() ;

}

if( ! function_exists( 'admin_refcheck' ) ) {

//Admin Referer Check By Marijuana(Rev.011)
function admin_refcheck($chkref = "") {
	if( empty( $_SERVER['HTTP_REFERER'] ) ) {
		return true ;
	} else {
		$ref = $_SERVER['HTTP_REFERER'];
	}
	$cr = XOOPS_URL;
	if ( $chkref != "" ) { $cr .= $chkref; }
	if ( strpos($ref, $cr) !== 0 ) { return false; }
	return true;
}

}

?>