123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- <?php
- /**********************************************************\
- | |
- | hprose |
- | |
- | Official WebSite: http://www.hprose.com/ |
- | http://www.hprose.net/ |
- | http://www.hprose.org/ |
- | |
- \**********************************************************/
- /**********************************************************\
- * *
- * HproseHttpServer.php *
- * *
- * hprose http server library for php5. *
- * *
- * LastModified: Nov 13, 2013 *
- * Author: Ma Bingyao <andot@hprfc.com> *
- * *
- \**********************************************************/
- require_once('HproseCommon.php');
- require_once('HproseIO.php');
- class HproseHttpServer {
- private $errorTable = array(E_ERROR => 'Error',
- E_WARNING => 'Warning',
- E_PARSE => 'Parse Error',
- E_NOTICE => 'Notice',
- E_CORE_ERROR => 'Core Error',
- E_CORE_WARNING => 'Core Warning',
- E_COMPILE_ERROR => 'Compile Error',
- E_COMPILE_WARNING => 'Compile Warning',
- E_USER_ERROR => 'User Error',
- E_USER_WARNING => 'User Warning',
- E_USER_NOTICE => 'User Notice',
- E_STRICT => 'Run-time Notice',
- E_RECOVERABLE_ERROR => 'Error');
- private $functions;
- private $funcNames;
- private $resultModes;
- private $simpleModes;
- private $debug;
- private $crossDomain;
- private $P3P;
- private $get;
- private $input;
- private $output;
- private $error;
- private $filter;
- private $simple;
- public $onBeforeInvoke;
- public $onAfterInvoke;
- public $onSendHeader;
- public $onSendError;
- public function __construct() {
- $this->functions = array();
- $this->funcNames = array();
- $this->resultModes = array();
- $this->simpleModes = array();
- $this->debug = false;
- $this->crossDomain = false;
- $this->P3P = false;
- $this->get = true;
- $this->filter = NULL;
- $this->simple = false;
- $this->error_types = E_ALL & ~E_NOTICE;
- $this->onBeforeInvoke = NULL;
- $this->onAfterInvoke = NULL;
- $this->onSendHeader = NULL;
- $this->onSendError = NULL;
- }
- /*
- __filterHandler & __errorHandler must be public,
- however we should never call them directly.
- */
- public function __filterHandler($data) {
- if (preg_match('/<b>.*? error<\/b>:(.*?)<br/', $data, $match)) {
- if ($this->debug) {
- $error = preg_replace('/<.*?>/', '', $match[1]);
- }
- else {
- $error = preg_replace('/ in <b>.*<\/b>$/', '', $match[1]);
- }
- $data = HproseTags::TagError .
- HproseFormatter::serialize(trim($error), true) .
- HproseTags::TagEnd;
- }
- if ($this->filter) $data = $this->filter->outputFilter($data);
- return $data;
- }
- public function __errorHandler($errno, $errstr, $errfile, $errline) {
- if ($this->debug) {
- $errstr .= " in $errfile on line $errline";
- }
- $this->error = $this->errorTable[$errno] . ": " . $errstr;
- $this->sendError();
- return true;
- }
- private function sendHeader() {
- if ($this->onSendHeader) {
- call_user_func($this->onSendHeader);
- }
- header("Content-Type: text/plain");
- if ($this->P3P) {
- header('P3P: CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi ' .
- 'CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL ' .
- 'UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"');
- }
- if ($this->crossDomain) {
- if (array_key_exists('HTTP_ORIGIN', $_SERVER) && $_SERVER['HTTP_ORIGIN'] != "null") {
- header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
- header("Access-Control-Allow-Credentials: true");
- }
- else {
- header('Access-Control-Allow-Origin: *');
- }
- }
- }
- private function sendError() {
- if ($this->onSendError) {
- call_user_func($this->onSendError, $this->error);
- }
- ob_clean();
- $this->output->write(HproseTags::TagError);
- $writer = new HproseSimpleWriter($this->output);
- $writer->writeString($this->error);
- $this->output->write(HproseTags::TagEnd);
- ob_end_flush();
- }
- private function doInvoke() {
- $simpleReader = new HproseSimpleReader($this->input);
- do {
- $functionName = $simpleReader->readString(true);
- $aliasName = strtolower($functionName);
- $resultMode = HproseResultMode::Normal;
- if (array_key_exists($aliasName, $this->functions)) {
- $function = $this->functions[$aliasName];
- $resultMode = $this->resultModes[$aliasName];
- $simple = $this->simpleModes[$aliasName];
- }
- elseif (array_key_exists('*', $this->functions)) {
- $function = $this->functions['*'];
- $resultMode = $this->resultModes['*'];
- $simple = $this->resultModes['*'];
- }
- else {
- throw new HproseException("Can't find this function " . $functionName . "().");
- }
- if ($simple === NULL) $simple = $this->simple;
- $writer = ($simple ? new HproseSimpleWriter($this->output) : new HproseWriter($this->output));
- $args = array();
- $byref = false;
- $tag = $simpleReader->checkTags(array(HproseTags::TagList,
- HproseTags::TagEnd,
- HproseTags::TagCall));
- if ($tag == HproseTags::TagList) {
- $reader = new HproseReader($this->input);
- $args = &$reader->readList();
- $tag = $reader->checkTags(array(HproseTags::TagTrue,
- HproseTags::TagEnd,
- HproseTags::TagCall));
- if ($tag == HproseTags::TagTrue) {
- $byref = true;
- $tag = $reader->checkTags(array(HproseTags::TagEnd,
- HproseTags::TagCall));
- }
- }
- if ($this->onBeforeInvoke) {
- call_user_func($this->onBeforeInvoke, $functionName, $args, $byref);
- }
- if (array_key_exists('*', $this->functions) && ($function === $this->functions['*'])) {
- $arguments = array($functionName, &$args);
- }
- elseif ($byref) {
- $arguments = array();
- for ($i = 0; $i < count($args); $i++) {
- $arguments[$i] = &$args[$i];
- }
- }
- else {
- $arguments = $args;
- }
- $result = call_user_func_array($function, $arguments);
- if ($this->onAfterInvoke) {
- call_user_func($this->onAfterInvoke, $functionName, $args, $byref, $result);
- }
- // some service functions/methods may echo content, we need clean it
- ob_clean();
- if ($resultMode == HproseResultMode::RawWithEndTag) {
- $this->output->write($result);
- return;
- }
- elseif ($resultMode == HproseResultMode::Raw) {
- $this->output->write($result);
- }
- else {
- $this->output->write(HproseTags::TagResult);
- if ($resultMode == HproseResultMode::Serialized) {
- $this->output->write($result);
- }
- else {
- $writer->reset();
- $writer->serialize($result);
- }
- if ($byref) {
- $this->output->write(HproseTags::TagArgument);
- $writer->reset();
- $writer->writeList($args);
- }
- }
- } while ($tag == HproseTags::TagCall);
- $this->output->write(HproseTags::TagEnd);
- ob_end_flush();
- }
- private function doFunctionList() {
- $functions = array_values($this->funcNames);
- $writer = new HproseSimpleWriter($this->output);
- $this->output->write(HproseTags::TagFunctions);
- $writer->writeList($functions);
- $this->output->write(HproseTags::TagEnd);
- ob_end_flush();
- }
- private function getDeclaredOnlyMethods($class) {
- $all = get_class_methods($class);
- if ($parent_class = get_parent_class($class)) {
- $inherit = get_class_methods($parent_class);
- $result = array_diff($all, $inherit);
- }
- else {
- $result = $all;
- }
- return $result;
- }
- public function addMissingFunction($function, $resultMode = HproseResultMode::Normal, $simple = NULL) {
- $this->addFunction($function, '*', $resultMode, $simple);
- }
- public function addFunction($function, $alias = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
- if (is_callable($function)) {
- if ($alias === NULL) {
- if (is_string($function)) {
- $alias = $function;
- }
- else {
- $alias = $function[1];
- }
- }
- if (is_string($alias)) {
- $aliasName = strtolower($alias);
- $this->functions[$aliasName] = $function;
- $this->funcNames[$aliasName] = $alias;
- $this->resultModes[$aliasName] = $resultMode;
- $this->simpleModes[$aliasName] = $simple;
- }
- else {
- throw new HproseException('Argument alias is not a string');
- }
- }
- else {
- throw new HproseException('Argument function is not a callable variable');
- }
- }
- public function addFunctions($functions, $aliases = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
- $aliases_is_null = ($aliases === NULL);
- $count = count($functions);
- if (!$aliases_is_null && $count != count($aliases)) {
- throw new HproseException('The count of functions is not matched with aliases');
- }
- for ($i = 0; $i < $count; $i++) {
- $function = $functions[$i];
- if ($aliases_is_null) {
- $this->addFunction($function, NULL, $resultMode, $simple);
- }
- else {
- $this->addFunction($function, $aliases[$i], $resultMode, $simple);
- }
- }
- }
- public function addMethod($methodname, $belongto, $alias = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
- if ($alias === NULL) {
- $alias = $methodname;
- }
- if (is_string($belongto)) {
- $this->addFunction(array($belongto, $methodname), $alias, $resultMode, $simple);
- }
- else {
- $this->addFunction(array(&$belongto, $methodname), $alias, $resultMode, $simple);
- }
- }
- public function addMethods($methods, $belongto, $aliases = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
- $aliases_is_null = ($aliases === NULL);
- $count = count($methods);
- if (is_string($aliases)) {
- $aliasPrefix = $aliases;
- $aliases = array();
- foreach ($methods as $name) {
- $aliases[] = $aliasPrefix . '_' . $name;
- }
- }
- if (!$aliases_is_null && $count != count($aliases)) {
- throw new HproseException('The count of methods is not matched with aliases');
- }
- for ($i = 0; $i < $count; $i++) {
- $method = $methods[$i];
- if (is_string($belongto)) {
- $function = array($belongto, $method);
- }
- else {
- $function = array(&$belongto, $method);
- }
- if ($aliases_is_null) {
- $this->addFunction($function, $method, $resultMode, $simple);
- }
- else {
- $this->addFunction($function, $aliases[$i], $resultMode, $simple);
- }
- }
- }
- public function addInstanceMethods($object, $class = NULL, $aliasPrefix = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
- if ($class === NULL) $class = get_class($object);
- $this->addMethods($this->getDeclaredOnlyMethods($class), $object, $aliasPrefix, $resultMode, $simple);
- }
- public function addClassMethods($class, $execclass = NULL, $aliasPrefix = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
- if ($execclass === NULL) $execclass = $class;
- $this->addMethods($this->getDeclaredOnlyMethods($class), $execclass, $aliasPrefix, $resultMode, $simple);
- }
- public function add() {
- $args_num = func_num_args();
- $args = func_get_args();
- switch ($args_num) {
- case 1: {
- if (is_callable($args[0])) {
- return $this->addFunction($args[0]);
- }
- elseif (is_array($args[0])) {
- return $this->addFunctions($args[0]);
- }
- elseif (is_object($args[0])) {
- return $this->addInstanceMethods($args[0]);
- }
- elseif (is_string($args[0])) {
- return $this->addClassMethods($args[0]);
- }
- break;
- }
- case 2: {
- if (is_callable($args[0]) && is_string($args[1])) {
- return $this->addFunction($args[0], $args[1]);
- }
- elseif (is_string($args[0])) {
- if (is_string($args[1]) && !is_callable(array($args[1], $args[0]))) {
- if (class_exists($args[1])) {
- return $this->addClassMethods($args[0], $args[1]);
- }
- else {
- return $this->addClassMethods($args[0], NULL, $args[1]);
- }
- }
- return $this->addMethod($args[0], $args[1]);
- }
- elseif (is_array($args[0])) {
- if (is_array($args[1])) {
- return $this->addFunctions($args[0], $args[1]);
- }
- else {
- return $this->addMethods($args[0], $args[1]);
- }
- }
- elseif (is_object($args[0])) {
- return $this->addInstanceMethods($args[0], $args[1]);
- }
- break;
- }
- case 3: {
- if (is_callable($args[0]) && is_null($args[1]) && is_string($args[2])) {
- return $this->addFunction($args[0], $args[2]);
- }
- elseif (is_string($args[0]) && is_string($args[2])) {
- if (is_string($args[1]) && !is_callable(array($args[0], $args[1]))) {
- return $this->addClassMethods($args[0], $args[1], $args[2]);
- }
- else {
- return $this->addMethod($args[0], $args[1], $args[2]);
- }
- }
- elseif (is_array($args[0])) {
- if (is_null($args[1]) && is_array($args[2])) {
- return $this->addFunctions($args[0], $args[2]);
- }
- else {
- return $this->addMethods($args[0], $args[1], $args[2]);
- }
- }
- elseif (is_object($args[0])) {
- return $this->addInstanceMethods($args[0], $args[1], $args[2]);
- }
- break;
- }
- throw new HproseException('Wrong arguments');
- }
- }
- public function isDebugEnabled() {
- return $this->debug;
- }
- public function setDebugEnabled($enable = true) {
- $this->debug = $enable;
- }
- public function isCrossDomainEnabled() {
- return $this->crossDomain;
- }
- public function setCrossDomainEnabled($enable = true) {
- $this->crossDomain = $enable;
- }
- public function isP3PEnabled() {
- return $this->P3P;
- }
- public function setP3PEnabled($enable = true) {
- $this->P3P = $enable;
- }
- public function isGetEnabled() {
- return $this->get;
- }
- public function setGetEnabled($enable = true) {
- $this->get = $enable;
- }
- public function getFilter() {
- return $this->filter;
- }
- public function setFilter($filter) {
- $this->filter = $filter;
- }
- public function getSimpleMode() {
- return $this->simple;
- }
- public function setSimpleMode($simple = true) {
- $this->simple = $simple;
- }
- public function getErrorTypes() {
- return $this->error_types;
- }
- public function setErrorTypes($error_types) {
- $this->error_types = $error_types;
- }
- public function handle() {
- if (!isset($HTTP_RAW_POST_DATA)) $HTTP_RAW_POST_DATA = file_get_contents("php://input");
- if ($this->filter) $HTTP_RAW_POST_DATA = $this->filter->inputFilter($HTTP_RAW_POST_DATA);
- $this->input = new HproseStringStream($HTTP_RAW_POST_DATA);
- $this->output = new HproseFileStream(fopen('php://output', 'wb'));
- set_error_handler(array(&$this, '__errorHandler'), $this->error_types);
- ob_start(array(&$this, "__filterHandler"));
- ob_implicit_flush(0);
- ob_clean();
- $this->sendHeader();
- if (($_SERVER['REQUEST_METHOD'] == 'GET') and $this->get) {
- return $this->doFunctionList();
- }
- elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
- try {
- switch ($this->input->getc()) {
- case HproseTags::TagCall: return $this->doInvoke();
- case HproseTags::TagEnd: return $this->doFunctionList();
- default: throw new HproseException("Wrong Request: \r\n" . $HTTP_RAW_POST_DATA);
- }
- }
- catch (Exception $e) {
- $this->error = $e->getMessage();
- if ($this->debug) {
- $this->error .= "\nfile: " . $e->getFile() .
- "\nline: " . $e->getLine() .
- "\ntrace: " . $e->getTraceAsString();
- }
- $this->sendError();
- }
- }
- $this->input->close();
- $this->output->close();
- }
- public function start() {
- $this->handle();
- }
- }
- ?>
|