Login   Register  
PHP Classes
elePHPant
Icontem

File: ACE.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Andrea Giammarchi  >  ACE  >  ACE.php  >  Download  
File: ACE.php
Role: Class source
Content type: text/plain
Description: ACE for the Server
Class: ACE
Generate Javascript to call PHP objects using AJAX
Author: By
Last change: Added better check for class names (accepts only /^[\w]+$/ words)
Date: 8 years ago
Size: 21,893 bytes
 

Contents

Class file image Download
<?php
/**_______________________________________
 *
 *    ACE :: Asynchronous Client Engine
 * ---------------------------------------
 * 
 *    ################################
 *    #   #                          #
 *    #  ###                         #
 *    #                              #
 *    #              #               #
 *    #             ###              #
 *    #           #######            #
 *    #         ###########          #
 *    #       ###############        #
 *    #     ###################      #
 *    #    #########    #########    #
 *    #     ######   #   ######      #
 *    #             ###              #
 *    #           #######            #
 *    #                              #
 *    #                              #
 *    #                         ###  #
 *    #                          #   #
 *    ################################
 *
 * ---------------------------------------
 * @author              Andrea Giammarchi
 * @site                www.devpro.it
 * @version             1.0b
 * ---------------------------------------
 * 
 * Copyright (c) 2006 Andrea Giammarchi - www.devpro.it
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated
 * documentation files (the "Software"),
 * to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * _______________________________________
 */



/**
 * CONFIGURATION :: PLEASE READ COMMENTS
 */

// GAME CONFIGURATION
$HAND_RULES = array(

	'DEBUG'	=> true,	// [true/false] creates a report for each class interaction
				// (requires a folder called "debug" with write permissions inside ACE.php place folder)
                                
	'UTF8'	=> false,	// [true/false] set ACE as an UTF8 compatible system
        
	'SPEED'	=> true,	// [true/false] increase server class inclusions, requires a dedicated name for classes
				// Example: class MyObject{} should be saved in a file called MyObject.class.php
                                // then suffix .class.php for each class file is required
                                
	'GZ'	=> false	// [true/false] try to use gz_compression to send responce to the client
				// NOTE: if enabled the progression value (0 to 100) will not be perfect
);



/**
 * ACE SYSTEM :: PLEASE DON'T MODIFY ANYTHING
 */

class ACE { // THE "CARD"
	
	/**
	 * ACE Class,
         * 	drived manager to parse and produce AJAX - PHP interaction
         *
         * @version	1.0
	 */
	
	var	$utf8 = false,		// is UTF8 enabled or not
		$continue = true,	// has any error
		$speed = false,		// uses direct require
		$gz = false,		// uses gz compression
		$dodebug = false,	// creates a debug file
		$debug = array(),	// debug informations
		$types = array(		// valid variable types
			's'=>'string', 'N'=>'null', 'O'=>'Class', 'b'=>'boolean', 'i'=>'integer', 'd'=>'float', 'a'=>'array', 'u'=>'undefined'
		);
	
	/**
	 * public constructor,
         * 	assigns properties to internal variables
         * 
         * new ACE(&config:array)
         *
         * @param	array		ACE configuration
	 */
	function ACE(&$settings) {
		$this->utf8 = &$settings['UTF8'];
		$this->speed = &$settings['SPEED'];
		$this->dodebug = &$settings['DEBUG'];
		$this->gz = !$this->dodebug && $settings['GZ'];
		if($this->dodebug) {
			@error_reporting(!defined('E_STRICT') ? 2047 : 2048);
			@set_error_handler(array(&$this, '__errorHandler'));
		}
	}
	
	/**
	 * public method,
         * 	includes external class file, parses input variables and if there aren't errors call the method with
         *      sent arguments.
         * 
         * self->callClassMethod(&className:string, &method:string):string
         *
         * @param	string		the name of the class to initializate
         * @param	string		the name of the method to use
         * @return	string		serialized value of method result or empty string if something is wrong
	 */
	function callClassMethod(&$className, &$method) {
		$i = 0;
		$istring = '_0';
		$hasinfo = false;
		$tmpclass = null;
		$args = $settings = $vars = $methodInfo = array();
		if($this->getClass($className)) {
			$tmpclass = new $className;
			$vars = get_object_vars($tmpclass);
			$settings = $this->getMethods($vars);
			if(in_array($method, $settings)) {
				$settings = $this->getMethodInformations($tmpclass, $method, $vars['methodTable']);
				if($settings['required'] === 0 || isset($_POST['_'.($settings['required'] - 1)])) {
					if(get_magic_quotes_gpc())
						$_POST = array_map(array(&$this, 'removePostMagicQuotes'), $_POST);
					$hasinfo = isset($settings['info']);
					while(isset($_POST[$istring]) && $this->goodRequestVariable($settings, $i, $_POST[$istring], $hasinfo)) {
						if($this->dodebug)
							array_push($methodInfo, '$args['.$i.'] = '.$_POST[$istring]);
						array_push($args, $this->unserialize($_POST[$istring]));
						$istring = '_'.(++$i);
					}
					if($this->continue) {
						$settings = array();
						$i = count($args);
						while($i)
							array_push($settings, '$args['.(--$i).']');
						$method .= '('.implode(',', array_reverse($settings)).')';
						eval('$istring=serialize(@$tmpclass->'.$method.');');
						if($this->dodebug)
							$method .= '<br />'.implode('<br />', $methodInfo);
					}
					elseif($this->dodebug)
						array_push($this->debug, 'ACE has killed itsself, bye bye.');
				}
				elseif($this->dodebug) {
					while(isset($_POST['_'.$i]))
						++$i;
					array_push($this->debug, $method.' method requires at least '.$settings['required'].' params and not '.$i);
				}
			}
			elseif($this->dodebug)
				array_push($this->debug, 'Choosed method is not availbale: '.$method);
		}
		elseif($this->dodebug)
			array_push($this->debug, 'Choosed Class or method is not valid: '.$className.'-&gt;'.$method);
		return $this->continue ? $istring : '';
	}
	
	/**
	 * public method,
         * 	verify class inclusion and parse methodTable informations.
         * 
         * self->exportClass(&className:string):array
         *
         * @param	string		the name of the class to export
         * @return	array		a list of every exported method (based on methodTable)
	 */
	function exportClass(&$className) {
		$tmpclass = null;
		$result = $settings = array();
		if($this->getClass($className)) {
			$tmpclass = new $className;
			$settings = get_object_vars($tmpclass);
			$settings = $this->getMethods($settings);
			for($a = 0, $b = count($settings); $a < $b; $a++)
				array_push($result, $this->utf8 ? utf8_encode($settings[$a]) : $settings[$a]);
		}
		elseif($this->dodebug)
			array_push($this->debug, 'Class '.$className.' is not valid');
		return $result;
	}
	
	/**
	 * public method,
         * 	try to include class file
         * 
         * self->getClass(&className:string):bool
         *
         * @param	string		the name of the class to include
         * @return	bool		true if class exists, false otherwise
	 */
	function getClass(&$className) {
		$classExists = false;
		if($this->speed) {
			@require $className.'.class.php';
			$classExists = class_exists($className);
		}
		else {
			$included = array();
			for($a = 0, $current = glob('ACE.php'), $files = glob('*.php'), $b = count($files); $a < $b; $a++) {
				if(!is_dir($files[$a]) && $files[$a] !== $current && !in_array($files[$a], $included)) {
					@require $files[$a];
					$classExists = class_exists($className);
					if($classExists)
						$a = $b;
					else
						$included = get_included_files();
				}
			}
		}
		return $classExists;
	}
	
	/**
	 * public method,
         * 	verify methodTable informations
         * 
         * self->getMethodInformations(&tmpclass:Object, &method:string, &vars:array):array
         *
         * @param	Object		an instance of the class
         * @param	string		the name of the method to use
         * @param	array		a list of each class variable (get_object_vars)
         * @return	array		a list of every required parameter and its type for choosed method
	 */
	function getMethodInformations(&$tmpclass, &$method, &$vars) {
		$i = 0;
		$result = array();
		if(
			isset($vars[$method]['arguments']) &&
			is_array($vars[$method]['arguments'])
		) {
			$result = array('info'=>array(), 'required'=>0);
			foreach($vars[$method]['arguments'] as $value) {
				array_push($result['info'], array(
					'type'=>(isset($value['type']) ? $this->parseType($value['type']) : 'u'),
					'required'=>(isset($value['required']) ? $value['required'] : false)
				));
				if($result['info'][$i]['required'])
					++$result['required'];
				++$i;
			}
		}
		return $result;
	}
	
	/**
	 * public method,
         * 	verify methodTable variable, if exists, gets every usable method
         * 
         * self->getMethods(&vars:array):array
         *
         * @param	array		a list of each class variable (get_object_vars)
         * @return	array		a list of every usable method defined in methodTable
	 */
	function getMethods(&$vars) {
		$result = array();
		if(isset($vars['methodTable']) && is_array($vars['methodTable'])) {
			foreach($vars['methodTable'] as $key => $value) {
				if(is_array($value) && (!isset($value['access']) || $value['access'] === 'remote'))
					array_push($result, $key);
			}
		}
		return $result;
	}
	
	/**
	 * public method,
         * 	verify if recieved variable is compatible with methodTable informations
         * 
         * self->goodRequestVariable(&settings:array, &i:int, &post:string, &hasinfo:bool):bool
         *
         * @param	array		a list of each methodtable valid information
         * @param	int		the index to use for informations
         * @param	string		recieved post variable
         * @param	bool		methodTable has informations
         * @return	bool		a boolean value that, if false, will kill a while loop and ACE execution
	 */
	function goodRequestVariable(&$settings, &$i, &$post, &$hasinfo) {
		if($this->continue)
			$this->continue = strlen($post) > 0;
		if($this->continue && $hasinfo && isset($settings['info'][$i])) {
			if($post{0} !== $settings['info'][$i]['type'] && $settings['info'][$i]['type'] !== 'u') {
				if($this->dodebug)
					array_push($this->debug, 'Variable #'.($i + 1).' of type '.$this->types[$settings['info'][$i]['type']].' is not defined or is not correct: '.$post);
				$this->continue = false;
			}
		}
		return $this->continue;
	}
	
	/**
	 * public method,
         * 	internal rapresentation of valid variable type
         * 
         * self->parseType(&type:string):string
         *
         * @param	string		a string defined on methodTable class array
         * @return	string		a single char that rappresents defined string type
	 */
	function parseType(&$type) {
		$result = 'u';
		switch(strtolower($type)) {
			case 'string':
				$result = 's';
				break;
			case 'int':
			case 'integer':
				$result = 'i';
				break;
			case 'null':
				$result = 'N';
			case 'class':
			case 'object':
				$result = 'O';
				break;
			case 'bool':
			case 'boolean':
				$result = 'b';
				break;
			case 'array':
				$result = 'a';
				break;
			case 'float':
			case 'double':
				$result = 'd';
				break;
		}
		return $result;
	}
	
	/**
	 * public method,
         * 	used to remove magic_quotes of $_POST array
         * 
         * self->removePostMagicQuotes(&post:mixed):mixed
         *
         * @param	mixed		array or a string
         * @return	string		stripslashed string or array to stripslash
	 */
	function removePostMagicQuotes(&$post) {
		return is_array($post) ? array_map(array(&$this, 'removePostMagicQuotes'), $post) : stripslashes($post);
	}
	
	/**
	 * public method,
         * 	verify that unserializzation works correctly and returns unserialized value.
         * 
         * self->unserialize(&post:string):mixed
         *
         * @param	string		variable serialized
         * @return	mixed		unserialized var
	 */
	function unserialize(&$post) {
		$result = $this->utf8 ? @unserialize($post) : @unserialize(utf8_decode($post));
		if($result === false && utf8_encode(serialize($result)) !== $post) {
			if($this->dodebug)
				array_push($this->debug, 'Unserialize Exception [utf8: '.($this->utf8 ? 'true' : 'false').'] with this var: '.$post);
			$this->continue = false;
		}
		return $result;
	}
	
	/**
	 * public method,
         * 	verify that unserializzation works correctly and returns unserialized value.
         * 
         * self->writeOutput(&output:string, htmloutput:bool):void
         *
         * @param	string		output to print
         * @param	bool		create html or javascript output output
	 */
	function writeOutput(&$output, $htmloutput) {
		if($this->gz)
			@ob_start('ob_gzhandler');
		if($htmloutput) {
			if($this->utf8)
				header('Content-type: text/html; charset=UTF-8');
			else
				header('Content-type: text/html; charset=ISO-8859-1');
			header('Content-Length: '.strlen($output));
			header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
			header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
			header('Cache-Control: no-store, no-cache, must-revalidate');
			header('Cache-Control: post-check=0, pre-check=0', false);
			header('Pragma: no-cache');
		}
		else {
			header('Content-type: text/javascript');
			header('Content-Length: '.strlen($output));
		}
		echo $output;
		if($this->gz)
			@ob_end_flush();
	}
	
	/**
	 * "private" method,
         * 	used to add errors to debugger
         * 
         * self->__errorHandler(errno:int, errstr:string, errfile:string, errline:int):void
         *
	 * @param	int		error number
         * @param	string		error message
         * @param	string		file that has trigged the error
         * @param	int		line of file
         */
	function __errorHandler($errno, $errstr, $errfile, $errline) {
		$errortype = array(
			1 	=> 'ERROR',
			2 	=> 'WARNING',
			4 	=> 'PARSE',
			8 	=> 'NOTICE',
			16	=> 'CORE_ERROR',
			32	=> 'CORE_WARNING',
			64	=> 'COMPILE_ERROR',
			128	=> 'COMPILE_WARNING',
			256	=> 'USER_ERROR',
			512	=> 'USER_WARNING',
			1024	=> 'USER_NOTICE',
			2047	=> 'ALL',
			2048	=> 'STRICT',
			4096	=> 'FUTURE'
		);
		array_push($this->debug, "[{$errno}] PHP {$errortype[$errno]} in line {$errline} of file {$errfile}<br />&nbsp; &nbsp; &nbsp; &nbsp; {$errstr}");
	}
}

class PAIR { // THE "HAND"
	
	/**
	 * PAIR Class,
         * 	ACE driver, makes ACE safe and manages debug output.
         *
         * @version	1.0
	 */


	/**
	 * public constructor,
         * 	REQUEST parser, ACE manager and DEBUG creator
         * 
         * new PAIR(&config:array)
         *
         * @param	array		ACE SYSTEM configuration
	 */
	function PAIR(&$settings) {
		
		$ace = &new ACE($settings);
		$call = '';
		$debugfile = '';
		$dodebug = false;
		$error = null;
		$file = null;
		$javascript = '';
		$output = '';
		$path = '';
		$report = array();
		$validClass = false;
		$methodExsists = isset($_GET['method']);
		if(isset($_GET['class']))
			$validClass = $this->verifyClass($_GET['class'], $methodExsists);
		
		if($ace->dodebug) {
			$path = $validClass ? 'debug/'.$_GET['class'].'.html' : 'debug/class.html';
			$file = @fopen($path, 'w');
			if($file) {
				$dodebug = true;
				$report = $this->getCommonErrors();
			}
		}
		if($validClass) {			
			if($dodebug)
				ob_start();
			if($methodExsists && $this->verifyMethod($_GET['class'], $_GET['method'])) {
				$output = $ace->callClassMethod($_GET['class'], $_GET['method']);
				if($output !== '')
					$ace->writeOutput($output, true);
				elseif($dodebug)
					array_push($ace->debug, $report['somethingwrong']);
			}
			else {
				if($dodebug)
					$debugfile = 'this.debug="'.substr($_SERVER['PHP_SELF'], 0, strpos(strtolower($_SERVER['PHP_SELF']), 'ace.php')).$path.'";';
				$call = $this->getJSCode($ace->utf8);
				for($class = explode('|', $_GET['class']), $a = 0, $b = count($class); $a < $b; $a++) {
					if($this->verifyClass($class[$a], $methodExsists)) {
						$output .= 'function '.$class[$a].'(){'.$debugfile;
						for($method = $ace->exportClass($class[$a]), $c = 0, $d = count($method); $c < $d; $c++) {
							$output .= 'this.'.$method[$c].'={call:function(){__ACE__(this,"'.$class[$a].'","'.$method[$c].'",arguments)}}';
							if(($c + 1) < $d)
								$output .= ',';
						}
						$output .= '};';
					}
					elseif($dodebug)
						array_push($ace->debug, $report['selfcall']);
				}
				$javascript = @file_get_contents('ACE.js');
				if($javascript) {
					$output = "{$javascript}\n{$call}\n{$output}";
					$ace->writeOutput($output, false);
				}
				elseif($dodebug)
					array_push($ace->debug, $report['missingfile']);
			}
		}
		elseif($dodebug)
			array_push($ace->debug, $report['selfcall']);
		if($dodebug) {
			$report = array();
			array_push($report, '<html><head><meta http-equiv="content-Type" content="text/html; charset='.($ace->utf8 ? 'UTF-8' : 'ISO-8859-1').'" /></head><body>');
			array_push($report,
				'<strong>ACE</strong> :: &quot;HAND&quot; INFORMATIONS :: '.gmdate('Y/m/d H:i:s').'<hr /><pre>',
				'<strong>Class:</strong> '.$_GET['class'].'<br /> <br />'
			);
			if(isset($_GET['method']))
				array_push($report, '<strong>Method:</strong> '.$_GET['method'].'<br /> <br />');
			if(count($ace->debug) === 0)
				array_push($report, '<strong>Any Error</strong>');
			else
				array_push($report, '<strong>Errors: </strong><br />'.implode('<br />', $ace->debug));
			array_push($report, '<br /> <br /><strong>Output:</strong><br />'.ob_get_contents().'</pre></body></html>');
			fwrite($file, implode("\r\n", $report));
			fclose($file);
			ob_end_flush();
		}
	}
	
	/**
	 * public method,
         * 	creates an associative array with common used method for debug
         * 
         * self->getCommonErrors(void):array
         *
         * @return	array		associative array with debug informations
	 */
	function getCommonErrors() {
		
		# POKER is "a joke" then this HAND "is a joke" too :-)
		return array(
			
			# means: ACE has recieved a $_GET['ACE'] parameter and cannot include itsself
			'selfcall'	=> 'Is this a bluff ? You just have an ACE in your hand and ACE wins the hand.',
			
			# means: file ACE.js not found and should be in the same ACE.php file directory
			'missingfile'	=> 'This game is for two players but ACE.js player is not present.',
			
			# means: ACE SYSTEM hasn't work correctly, something was wrong
			'somethingwrong'=> 'Any winner for this hand, let\'s start another one ?'
		);
	}
	
	/**
	 * public method,
         * 	generates javascript code
         * 
         * self->getJSCode(&utf8:bool):string
         *
         * @param	boolean		ACE uses utf8 or not
         * @return	string		runtime cross-browser javascript function rappresentation.
	 */
	function getJSCode(&$utf8) {
		$utf8string = $utf8 ? 'true' : 'false';
		return (
'function __ACE__(self,className,methodName,args){
function onProgress(){var p=ace.getProgress();if(self.progress)self.progress(p);if(p===100){clearInterval(i);ace.onLoadComplete()}};
var i=0,ace=new ACE('.$utf8string.');
ace.onError=function(s){if(self.error)self.error("Error #".concat(s))};
ace.onLoad=function(r){if(self.result)self.result(r)};
ace.sendAndLoad("'.$_SERVER['PHP_SELF'].'".concat("?class=",encodeURIComponent(className),"&method=",encodeURIComponent(methodName)),args);
i=setInterval(onProgress,10);};'
		);
	}

	/**
	 * public method,
         * 	check if required class is different from ACE then is safe for this file
         * 
         * self->verifyClass(&className:string):bool
         *
         * @param	string		the name of required class
         * @return	bool		verify passed or not
	 */
	function verifyClass(&$className, &$methodExsists) {
		return (preg_match('/^[\w]+$/', $className) && strtoupper($className) !== 'ACE') || (!$methodExsists && preg_match('/^[\w|]+$/', $className));
	}
	
	/**
	 * public method,
         * 	check if required method is different from constructor and if has correct chars
         * 
         * self->verifyMethod(&className:string, &method:string):bool
         *
         * @param	string		the name of required class
         * @param	string		the name of required method for required class
         * @return	bool		verify passed or not
	 */
	function verifyMethod(&$className, &$method) {
		return preg_match('/^[\w]+$/', $method) && strtoupper($method) !== strtoupper($className);
	}
}

// THE "GAME"
	/** LET'S START THIS GAME */
		new PAIR($HAND_RULES);
	/** YOU WIN ? ... THEN PLAY ANOTHER HAND ! */
?>