<?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.'->'.$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 /> {$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> :: "HAND" 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 ! */
?>
|