* @author Dominique Stender * @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint * @version $id: cpaint2.inc.php 311 2006-09-30 08:21:25Z saloon12yrd $ */ //---- includes ---------------------------------------------------------------- /** * @include JSON */ require_once(dirname(__FILE__) . '/json.php'); //---- variables --------------------------------------------------------------- $GLOBALS['__cpaint_json'] = new JSON(); //---- error reporting --------------------------------------------------------- error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING); //---- classes ----------------------------------------------------------------- /** * cpaint base class. * * @package CPAINT * @access public * @author Paul Sullivan * @author Dominique Stender * @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint * @version 2.1.0 */ class cpaint { /** * version number * * @access private * @var string $version */ public $version = '2.1.0'; /** * response type. * * @access protected * @var string $response_type */ public $response_type; /** * the basenode ajaxResponse. * * @access protected * @var object $basenode */ public $basenode; /** * list of registered methods available through the CPAINT API * * @access protected * @var array $api_functions */ public $api_functions; /** * list of registered complex types used in the CPAINT API * * @access protected * @var array $api_datatypes */ public $api_datatypes; /** * whether or not the CPAINT API generates a WSDL when called with ?wsdl querystring * * @access private * @var boolean $use_wsdl */ public $use_wsdl; /** * PHP4 constructor. * * @access public * @return void */ public function cpaint() { $this->__construct(); } /** * PHP 5 constructor. * * @access public * @return void * @todo -o"Dominique Stender" -ccpaint implement a better debugging */ public function __construct() { // initialize properties $this->basenode = new cpaint_node(); $this->basenode->set_name('ajaxResponse'); $this->basenode->set_attribute('id', ''); $this->basenode->set_encoding('UTF-8'); $this->response_type = 'TEXT'; $this->api_functions = array(); $this->api_datatypes = array(); /* $this->use_wsdl = true; $this->complex_type(array( 'name' => 'cpaintResponseType', 'type' => 'restriction', // (restriction|complex|list) 'base_type' => 'string', // scalar type of all values, e.g. 'string', for type = (restriction|list) only 'values' => array( // for type = 'restriction' only: list of allowed values 'XML', 'TEXT', 'OBJECT', 'E4X', 'JSON', ), ) ); $this->complex_type(array( 'name' => 'cpaintDebugLevel', 'type' => 'restriction', 'base_type' => 'long', 'values' => array( -1, 0, 1, 2 ), ) ); $this->complex_type(array( 'name' => 'cpaintDebugMessage', 'type' => 'list', 'base_type' => 'string', ) ); $this->complex_type(array( 'name' => 'cpaintRequestHead', 'type' => 'complex', 'struct' => array( 0 => array('name' => 'functionName', 'type' => 'string'), 1 => array('name' => 'responseType', 'type' => 'cpaintResponseType'), 2 => array('name' => 'debugLevel', 'type' => 'cpaintDebugLevel'), ), ) ); // $this->complex_type(array( 'name' => 'cpaintResponseHead', 'type' => 'complex', 'struct' => array( 0 => array('name' => 'success', 'type' => 'boolean'), 1 => array('name' => 'debugger', 'type' => 'cpaintDebugMessage'), ), ) ); */ // determine response type if (isset($_REQUEST['cpaint_response_type'])) { $this->response_type = htmlentities(strip_tags(strtoupper((string) $_REQUEST['cpaint_response_type']))); } // end: if } /** * calls the user function responsible for this specific call. * * @access public * @param string $input_encoding input data character encoding, default is UTF-8 * @return void */ public function start($input_encoding = 'UTF-8') { $user_function = ''; $arguments = array(); // work only if there is no API version request if (!isset($_REQUEST['api_query']) && !isset($_REQUEST['wsdl'])) { $this->basenode->set_encoding($input_encoding); if ($_REQUEST['cpaint_function'] != '') { $user_function = $_REQUEST['cpaint_function']; if (isset($_REQUEST['cpaint_argument'])) { $arguments = $_REQUEST['cpaint_argument']; } } // perform character conversion on every argument foreach ($arguments as $key => $value) { if (get_magic_quotes_gpc() == true) { $value = stripslashes($value); } // end: if // convert from JSON string if it is an object or an array if (preg_match('/^(\[|\{).*(\]|\})$/', $value)) { $arguments[$key] = $GLOBALS['__cpaint_json']->parse($value); } // end: if } // end: foreach $arguments = cpaint_transformer::decode_array($arguments, $this->basenode->get_encoding()); if (is_array($this->api_functions[$user_function]) && is_callable($this->api_functions[$user_function]['call'])) { // a valid API function is to be called call_user_func_array($this->api_functions[$user_function]['call'], $arguments); } else if ($user_function != '') { // desired function is not registered as API function $this->basenode->set_data('[CPAINT] A function name was passed that is not allowed to execute on this server.'); } } // end: if } /** * generates and prints the response based on response type supplied by the frontend. * * @access public * @return void */ public function return_data() { // send appropriate headers to avoid caching header('Expires: Fri, 14 Mar 1980 20:53:00 GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); header('X-Powered-By: CPAINT v' . $this->version . '/PHP v' . phpversion()); // work only if there is no API version request if (!isset($_REQUEST['api_query']) /* && !isset($_REQUEST['wsdl']) */) { // trigger generation of response switch (trim($this->response_type)) { case 'TEXT': header('Content-type: text/plain; charset=' . cpaint_transformer::find_output_charset($this->basenode->get_encoding())); echo cpaint_transformer::toString($this->basenode); break; case 'JSON': header('Content-type: text/plain; charset=' . cpaint_transformer::find_output_charset($this->basenode->get_encoding())); echo cpaint_transformer::toJSON($this->basenode); break; case 'OBJECT': case 'E4X': case 'XML': header('Content-type: text/xml; charset=' . cpaint_transformer::find_output_charset($this->basenode->get_encoding())); echo 'basenode->get_encoding()) . '"?>' . cpaint_transformer::toXML($this->basenode); break; default: echo 'ERROR: invalid response type \'' . $this->response_type . '\''; } // end: switch } elseif (isset($_REQUEST['api_query'])) { // API version request header('Content-type: text/plain; charset=ISO-8859-1'); echo 'CPAINT v' . $this->version . '/PHP v' . phpversion(); /* } elseif ($this->use_wsdl == true && isset($_REQUEST['wsdl'])) { if (is_file(dirname(__FILE__) . '/cpaint2.wsdl.php') && is_readable(dirname(__FILE__) . '/cpaint2.wsdl.php')) { require_once(dirname(__FILE__) . '/cpaint2.wsdl.php'); if (class_exists('cpaint_wsdl')) { // create new instance of WSDL library $wsdl = new cpaint_wsdl(); // build WSDL info header('Content-type: text/xml; charset=UTF-8'); echo $wsdl->generate($this->api_functions, $this->api_datatypes); } else { header('Content-type: text/plain; charset=ISO-8859-1'); echo 'WSDL generator is unavailable'; } // end: if } else { header('Content-type: text/plain; charset=ISO-8859-1'); echo 'WSDL generator is unavailable'; } // end: if */ } // end: if } /** * registers a new function or method as part of the CPAINT API * * @access public * @param mixed $func function name, array(&$object, 'function_name') or array('class', 'function_name') * @param string $alias alias name for the function. Will be used by the frontend. * @param array $input function input parameters (not yet used by CPAINT and subject to change) * @param array $output function output format (not yed used by CPAINT and subject to change) * @param string $comment description of the functionality * @return boolean * @version 1.0.1 16.09.2006 23:07:44 [dstender] Added alias functionality. */ public function register($func, $alias = '', $input = array(), $output = array(), $comment = '') { $return_value = false; $alias = (string) $alias; $input = (array) $input; $output = (array) $output; $comment = (string) $comment; $callable = ''; if (is_array($func) && (is_object($func[0]) || is_string($func[0])) && is_string($func[1]) && is_callable($func)) { // set correct function name if alias is used. if ($alias != '') { $callable = $alias; } else { $callable = $func[1]; } // end: if // calling a method of an object $this->api_functions[$callable] = array( 'call' => $func, 'input' => $input, 'output' => $output, 'comment' => $comment, ); $return_value = true; } elseif (is_string($func)) { // set correct function name if alias is used. if ($alias != '') { $callable = $alias; } else { $callable = $func; } // end: if // calling a standalone function $this->api_functions[$callable] = array( 'call' => $func, 'input' => $input, 'output' => $output, 'comment' => $comment, ); $return_value = true; } // end: if return $return_value; } /** * unregisters a function that is currently part of the CPAINT API. * * proves useful when the same set of functions is to be used in the * frontend and in some kind of administration environment. you might * want to unregister a few (admin) functions for the frontend in this * case. * * Note that if you supplied an alias when registering a method, you must * use the alias to unregister the function / method. * * @access public * @param string $func function name * @return boolean * @see cpaint:register() * @version 1.0.1 16.09.2006 23:10:58 [dstender] Extended PHPDoc for use of aliases. */ public function unregister($func) { $retval = false; if (is_array($this->api_functions[$func])) { unset($this->api_functions[$func]); } // end: if return $retval; } /** * registers a complex data type * * @access public * @param array $schema schema definition for the complex type * @return boolean public function complex_type($schema) { $return_value = false; $schema = (array) $schema; if ($schema['name'] != '' && in_array($schema['type'], array('restriction', 'complex', 'list'))) { $this->api_datatypes[] = $schema; $return_value = true; } // end: if return $return_value; } */ /** * switches the generation of WSDL on/off. default is on * * @access public * @param boolean $state state of WSDL generation * @return void public function use_wsdl($state) { $this->use_wsdl = (boolean) $state; } */ /** * adds a new subnode to the basenode. * * will return a reference to it for further processing. * * @access public * @param string $nodename name of the new node * @param string $id id of the new node * @return object */ public function &add_node($nodename, $id = '') { return $this->basenode->add_node($nodename, $id); } /** * assigns textual data to the basenode. * * @access public * @param mixed $data data to assign to this node * @return void */ public function set_data($data) { $this->basenode->set_data($data); } /** * returns the data assigned to the basenode. * * @access public * @return mixed */ public function get_data() { return $this->basenode->get_data(); } /** * sets the id property of the basenode. * * @deprecated deprecated since version 2.0.0 * @access public * @param string $id the id * @return void */ public function set_id($id) { $this->basenode->set_attribute('id', $id); } /** * gets the id property of the basenode. * * @deprecated deprecated since version 2.0.0 * @access public * @return string */ public function get_id() { return $this->basenode->get_attribute('id'); } /** * adds a new attribute to the basenode. * * @access public * @param string $name attribute name * @param mixed $value attribute value * @return void */ public function set_attribute($name, $value) { $this->basenode->set_attribute($name, $value); } /** * retrieves an attribute of the basenode by name. * * @access public * @param string $name attribute name * @return string */ public function get_attribute($name) { return $this->basenode->get_attributes($name); } /** * set name property of the basenode. * * @access public * @param string $name the name * @return void */ public function set_name($name) { $this->basenode->set_name($name); } /** * get name property of the basenode. * * @access public * @return string */ public function get_name() { return $this->basenode->get_name(); } /** * returns the response type as requested by the client * * @access public * @return string */ public function get_response_type() { return $this->response_type; } } ?>