<?php
/**
 * Filters modify the AMF message has a whole, actions modify the AMF message PER BODY
 * This allows batching of calls
 * 
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 * @copyright (c) 2003 amfphp.org
 * @package flashservices
 * @subpackage filters
 * @version $Id: Filters.php,v 1.6 2005/04/02   18:37:51 pmineault Exp $
 */

/**
 * required files
 */ 
require_once(AMFPHP_BASE . "io/AMFDeserializer.php");
require_once(AMFPHP_BASE . "io/AMFSerializer.php");
require_once(AMFPHP_BASE . 'util/TraceHeader.php');

/**
 * DeserializationFilter has the job of taking the raw input stream and converting in into valid php objects.
 * 
 * The DeserializationFilter is just part of a set of Filter chains used to manipulate the raw data.  Here we
 * get the input stream and convert it to php objects using the helper class AMFInputStream.
 */
function deserializationFilter(&$amf) {
	$deserializer = new AMFDeserializer($amf->rawData); // deserialize the data
	$deserializer->deserialize($amf); // run the deserializer
	
	//Add some headers
	$headers = $amf->_headerTable;
	if(isset($headers) && is_array($headers))
	{
		foreach($headers as $key => $value)
		{
			Headers::setHeader($value->name, $value->value);
		}
	}
	
	//Set as a describe service
	$describeHeader = $amf->getHeader(AMFPHP_SERVICE_BROWSER_HEADER);
   
	if ($describeHeader !== false) {
		if($GLOBALS['amfphp']['disableDescribeService'])
		{
			//Exit 
			trigger_error("Service description not allowed", E_USER_ERROR);
			die();
		}
		$bodyCopy = &$amf->getBodyAt(0);
		$bodyCopy->setSpecialHandling('describeService');
		$bodyCopy->noExec = true;
	}
}

/**
 * AuthenticationFilter looks at the credential headers, starts sessions, etc.
 */
function authenticationFilter (&$amf) {
	$authHeader = $amf->getHeader(AMFPHP_CREDENTIALS_HEADER);

	if ($authHeader !== false && $authHeader->value !== AMFPHP_CLEARED_CREDENTIALS) {
		//In PHP5, objects are always pass-by-ref, hence this branch
		if(AMFPHP_PHP5)
		{
			$bodyCopy = clone($amf->getBodyAt(0));
		}
		else
		{
			$bodyCopy = $amf->getBodyAt(0);
		}
		
		$uri = $bodyCopy->targetURI;
		$lpos = strrpos($uri, ".");
		$cp = substr($uri, 0, $lpos + 1) . "_authenticate";
		$bodyCopy->targetURI = $cp;
		$bodyCopy->setSpecialHandling('auth');
		$val = $authHeader->value;
		$bodyCopy->setValue($val);
		$amf->addBodyAt(0, $bodyCopy);
		
		//Make it so that the data will stop being transmitted
		$clearHeader = array('name' => 'Credentials', 'mustUnderstand' => false, 
			'data' => AMFPHP_CLEARED_CREDENTIALS);
		$outHeader = new AMFHeader("RequestPersistentHeader", true, $clearHeader);
		$amf->addOutgoingHeader($outHeader);
	}

	session_start();
	$session_id = session_id();
	if(!strpos($_SERVER['QUERY_STRING'], $session_id) !== FALSE)
	{
		/**
		 Instead of trying to guess if using https, 
		 just use AppendTogGatewayUrl instead
		 of ReplaceGatewayUrl
		*/
		$outHeader = new AMFHeader("AppendToGatewayUrl", false, "?" . ini_get('session.name') . "=" . $session_id);
		$amf->addOutgoingHeader($outHeader);
	}
}

/**
 * Executes each of the bodys
 */
function batchProcessFilter(&$amf)
{
	$bodycount = $amf->numBody();
	
	for ($i = 0; $i < $bodycount; $i++) {
		$bodyObj = &$amf->getBodyAt($i);
		$actions = $GLOBALS['amfphp']['actions'];
		foreach($actions as $key => $action)
		{
			$results = $action($bodyObj);
			if($results === false)
			{
				break;
			}
		}
	}
	
	$bodycount = $amf->numBody();
	
	for ($i = 0; $i < $bodycount; $i++) {
		$bodyObj = &$amf->getBodyAt($i);
		if($bodyObj->getSpecialHandling() == 'auth' && $bodyObj->getResults() === NULL)
		{
			$amf->removeBodyAt($i);
			break;
		}
	}
}

/**
 * Adds debugging information to outgoing packet
 */
function debugFilter (&$amf) {
	//Add trace headers before outputting
	if(!$GLOBALS['amfphp']['isFlashComm'] && !$GLOBALS['amfphp']['disableTrace'] && count(NetDebug::getTraceStack()) != 0)
	{
		//Get the last body in the stack
		$body = &$amf->getBodyAt($amf->numBody() - 1);
		
		$headers = new AMFBody(NULL, $body->responseIndex, NULL); // create a new amf body
		$headers->responseURI = $body->responseIndex . "/onDebugEvents"; // set the response uri of this body
		$headerresults = array(); // create a result array
		$headerresults[0] = array(); // create a sub array in results (CF seems to do this, don't know why)
		
		$ts = NetDebug::getTraceStack();
		$headerresults[0][] = new TraceHeader($ts);
		
		$headers->setResults($headerresults); // set the results.
		$amf->addBodyAt(0, $headers);
	}
}

/**
 * Serializes the object
 */
function serializationFilter (&$amf) {
	$serializer = new AMFSerializer(); // Create a serailizer around the output stream
	$result = $serializer->serialize($amf); // serialize the data
	$amf->outputStream = $result;
}
?>