PHP Classes

File: ACE.php

Recommend this page to a friend!
  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: 16 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 ! */ ?>