* $response = Horde_RPC::request('xmlrpc', * 'http://localhost:80/horde/rpc.php' * 'contacts.search', * array(array('jan'), array('localsql'), * array('name', 'email')), * array('user' => Auth::getAuth(), * 'pass' => Auth::getCredential('password'))); * * * $Horde: framework/RPC/RPC.php,v 1.14 2006/01/01 21:10:10 jan Exp $ * * Copyright 2002-2006 Jan Schneider * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * * @author Jan Schneider * @since Horde 3.0 * @package Horde_RPC */ class Horde_RPC { /** * Whether we need an authorized user or not. * * @access protected * @var boolean */ var $_authorize = true; /** * RPC server constructor * * @access private * @return object An RPC server instance. */ function Horde_RPC() { register_shutdown_function(array($this, 'shutdown')); } /** * Cleans up the RPC server. * * @abstract */ function shutdown() { } /** * Check authentication. Different backends may handle * authentication in different ways. The base class implementation * checks for HTTP Authentication against the Horde auth setup. * * @return boolean Returns true if authentication is successful. * Should send appropriate "not authorized" headers * or other response codes/body if auth fails, * and take care of exiting. */ function authorize() { if (!$this->_authorize) { return true; } $auth = &Auth::singleton($GLOBALS['conf']['auth']['driver']); if (isset($_SERVER['PHP_AUTH_USER'])) { $user = $_SERVER['PHP_AUTH_USER']; $pass = $_SERVER['PHP_AUTH_PW']; } if (!isset($user) || !$auth->authenticate($user, array('password' => $pass))) { header('WWW-Authenticate: Basic realm="Horde RPC"'); header('HTTP/1.0 401 Unauthorized'); echo '401 Unauthorized'; exit; } return true; } /** * Get the request body input. Different RPC backends can override * this to return an open stream to php://stdin, for instance - * whatever is easiest to handle in the getResponse() method. * * The base class implementation looks for $HTTP_RAW_POST_DATA and * returns that if it's available; otherwise, it returns the * contents of php://stdin. * * @return mixed The input - a string (default), a filehandle, etc. */ function getInput() { if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) { return $GLOBALS['HTTP_RAW_POST_DATA']; } else { return implode("\r\n", file('php://input')); } } /** * Sends an RPC request to the server and returns the result. * * @param string The raw request string. * * @return string The XML encoded response from the server. */ function getResponse($request) { return _("not implemented"); } /** * Get the Content-Type of the response. * * @return string The MIME Content-Type of the RPC response. */ function getResponseContentType() { return 'text/xml'; } /** * Builds an RPC request and sends it to the RPC server. * * This statically called method is actually the RPC client. * * @param string $driver The protocol driver to use. Currently 'soap' * and 'xmlrpc' are available. * @param string $url The path to the RPC server on the called host. * @param string $method The method to call. * @param array $params A hash containing any necessary parameters for * the method call. * @param $options Associative array of parameters depending on * the selected protocol driver. * * @return mixed The returned result from the method or a PEAR * error object on failure. */ function request($driver, $url, $method, $params = null, $options = array()) { if (is_array($driver)) { list($app, $driver) = $driver; } $driver = basename($driver); if (!empty($app)) { require_once $app . '/lib/RPC/' . $driver . '.php'; } elseif (@file_exists(dirname(__FILE__) . '/RPC/' . $driver . '.php')) { require_once dirname(__FILE__) . '/RPC/' . $driver . '.php'; } else { @include_once 'Horde/RPC/' . $driver . '.php'; } $class = 'Horde_RPC_' . $driver; if (class_exists($class)) { return call_user_func(array($class, 'request'), $url, $method, $params, $options); } else { require_once 'PEAR.php'; return PEAR::raiseError('Class definition of ' . $class . ' not found.'); } } /** * Attempts to return a concrete RPC server instance based on * $driver. * * @param mixed $driver The type of concrete RPC subclass to return. If * $driver is an array, then we will look in * $driver[0]/lib/RPC/ for the subclass * implementation named $driver[1].php. * @param array $params A hash containing any additional configuration or * connection parameters a subclass might need. * * @return Horde_RPC The newly created concrete Horde_RPC server instance, * or a PEAR_Error on an error. */ function &factory($driver, $params = null) { if (is_array($driver)) { list($app, $driver) = $driver; } $driver = basename($driver); if (!empty($app)) { require_once $app . '/lib/RPC/' . $driver . '.php'; } elseif (@file_exists(dirname(__FILE__) . '/RPC/' . $driver . '.php')) { require_once dirname(__FILE__) . '/RPC/' . $driver . '.php'; } else { @include_once 'Horde/RPC/' . $driver . '.php'; } $class = 'Horde_RPC_' . $driver; if (class_exists($class)) { $rpc = new $class($params); } else { require_once 'PEAR.php'; $rpc = PEAR::raiseError('Class definition of ' . $class . ' not found.'); } return $rpc; } /** * Attempts to return a reference to a concrete RPC server * instance based on $driver. It will only create a new instance * if no RPC server instance with the same parameters currently * exists. * * This should be used if multiple RPC servers (and thus, multiple RPC * server instances) are required. * * This method must be invoked as: $var = &Horde_RPC::singleton() * * @param string $driver The type of concrete RPC subclass to return. * @param array $params A hash containing any additional configuration or * connection parameters a subclass might need. * * @return Horde_RPC The concrete Horde_RPC server reference, or a * PEAR_Error on an error. */ function &singleton($driver, $params = null) { static $instances; if (!isset($instances)) { $instances = array(); } $signature = serialize(array($driver, $params)); if (!array_key_exists($signature, $instances)) { $instances[$signature] = &Horde_RPC::factory($driver, $params); } return $instances[$signature]; } }