HproseHttpServer.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. <?php
  2. /**********************************************************\
  3. | |
  4. | hprose |
  5. | |
  6. | Official WebSite: http://www.hprose.com/ |
  7. | http://www.hprose.net/ |
  8. | http://www.hprose.org/ |
  9. | |
  10. \**********************************************************/
  11. /**********************************************************\
  12. * *
  13. * HproseHttpServer.php *
  14. * *
  15. * hprose http server library for php5. *
  16. * *
  17. * LastModified: Nov 13, 2013 *
  18. * Author: Ma Bingyao <andot@hprfc.com> *
  19. * *
  20. \**********************************************************/
  21. require_once('HproseCommon.php');
  22. require_once('HproseIO.php');
  23. class HproseHttpServer {
  24. private $errorTable = array(E_ERROR => 'Error',
  25. E_WARNING => 'Warning',
  26. E_PARSE => 'Parse Error',
  27. E_NOTICE => 'Notice',
  28. E_CORE_ERROR => 'Core Error',
  29. E_CORE_WARNING => 'Core Warning',
  30. E_COMPILE_ERROR => 'Compile Error',
  31. E_COMPILE_WARNING => 'Compile Warning',
  32. E_USER_ERROR => 'User Error',
  33. E_USER_WARNING => 'User Warning',
  34. E_USER_NOTICE => 'User Notice',
  35. E_STRICT => 'Run-time Notice',
  36. E_RECOVERABLE_ERROR => 'Error');
  37. private $functions;
  38. private $funcNames;
  39. private $resultModes;
  40. private $simpleModes;
  41. private $debug;
  42. private $crossDomain;
  43. private $P3P;
  44. private $get;
  45. private $input;
  46. private $output;
  47. private $error;
  48. private $filter;
  49. private $simple;
  50. public $onBeforeInvoke;
  51. public $onAfterInvoke;
  52. public $onSendHeader;
  53. public $onSendError;
  54. public function __construct() {
  55. $this->functions = array();
  56. $this->funcNames = array();
  57. $this->resultModes = array();
  58. $this->simpleModes = array();
  59. $this->debug = false;
  60. $this->crossDomain = false;
  61. $this->P3P = false;
  62. $this->get = true;
  63. $this->filter = NULL;
  64. $this->simple = false;
  65. $this->error_types = E_ALL & ~E_NOTICE;
  66. $this->onBeforeInvoke = NULL;
  67. $this->onAfterInvoke = NULL;
  68. $this->onSendHeader = NULL;
  69. $this->onSendError = NULL;
  70. }
  71. /*
  72. __filterHandler & __errorHandler must be public,
  73. however we should never call them directly.
  74. */
  75. public function __filterHandler($data) {
  76. if (preg_match('/<b>.*? error<\/b>:(.*?)<br/', $data, $match)) {
  77. if ($this->debug) {
  78. $error = preg_replace('/<.*?>/', '', $match[1]);
  79. }
  80. else {
  81. $error = preg_replace('/ in <b>.*<\/b>$/', '', $match[1]);
  82. }
  83. $data = HproseTags::TagError .
  84. HproseFormatter::serialize(trim($error), true) .
  85. HproseTags::TagEnd;
  86. }
  87. if ($this->filter) $data = $this->filter->outputFilter($data);
  88. return $data;
  89. }
  90. public function __errorHandler($errno, $errstr, $errfile, $errline) {
  91. if ($this->debug) {
  92. $errstr .= " in $errfile on line $errline";
  93. }
  94. $this->error = $this->errorTable[$errno] . ": " . $errstr;
  95. $this->sendError();
  96. return true;
  97. }
  98. private function sendHeader() {
  99. if ($this->onSendHeader) {
  100. call_user_func($this->onSendHeader);
  101. }
  102. header("Content-Type: text/plain");
  103. if ($this->P3P) {
  104. header('P3P: CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi ' .
  105. 'CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL ' .
  106. 'UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"');
  107. }
  108. if ($this->crossDomain) {
  109. if (array_key_exists('HTTP_ORIGIN', $_SERVER) && $_SERVER['HTTP_ORIGIN'] != "null") {
  110. header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
  111. header("Access-Control-Allow-Credentials: true");
  112. }
  113. else {
  114. header('Access-Control-Allow-Origin: *');
  115. }
  116. }
  117. }
  118. private function sendError() {
  119. if ($this->onSendError) {
  120. call_user_func($this->onSendError, $this->error);
  121. }
  122. ob_clean();
  123. $this->output->write(HproseTags::TagError);
  124. $writer = new HproseSimpleWriter($this->output);
  125. $writer->writeString($this->error);
  126. $this->output->write(HproseTags::TagEnd);
  127. ob_end_flush();
  128. }
  129. private function doInvoke() {
  130. $simpleReader = new HproseSimpleReader($this->input);
  131. do {
  132. $functionName = $simpleReader->readString(true);
  133. $aliasName = strtolower($functionName);
  134. $resultMode = HproseResultMode::Normal;
  135. if (array_key_exists($aliasName, $this->functions)) {
  136. $function = $this->functions[$aliasName];
  137. $resultMode = $this->resultModes[$aliasName];
  138. $simple = $this->simpleModes[$aliasName];
  139. }
  140. elseif (array_key_exists('*', $this->functions)) {
  141. $function = $this->functions['*'];
  142. $resultMode = $this->resultModes['*'];
  143. $simple = $this->resultModes['*'];
  144. }
  145. else {
  146. throw new HproseException("Can't find this function " . $functionName . "().");
  147. }
  148. if ($simple === NULL) $simple = $this->simple;
  149. $writer = ($simple ? new HproseSimpleWriter($this->output) : new HproseWriter($this->output));
  150. $args = array();
  151. $byref = false;
  152. $tag = $simpleReader->checkTags(array(HproseTags::TagList,
  153. HproseTags::TagEnd,
  154. HproseTags::TagCall));
  155. if ($tag == HproseTags::TagList) {
  156. $reader = new HproseReader($this->input);
  157. $args = &$reader->readList();
  158. $tag = $reader->checkTags(array(HproseTags::TagTrue,
  159. HproseTags::TagEnd,
  160. HproseTags::TagCall));
  161. if ($tag == HproseTags::TagTrue) {
  162. $byref = true;
  163. $tag = $reader->checkTags(array(HproseTags::TagEnd,
  164. HproseTags::TagCall));
  165. }
  166. }
  167. if ($this->onBeforeInvoke) {
  168. call_user_func($this->onBeforeInvoke, $functionName, $args, $byref);
  169. }
  170. if (array_key_exists('*', $this->functions) && ($function === $this->functions['*'])) {
  171. $arguments = array($functionName, &$args);
  172. }
  173. elseif ($byref) {
  174. $arguments = array();
  175. for ($i = 0; $i < count($args); $i++) {
  176. $arguments[$i] = &$args[$i];
  177. }
  178. }
  179. else {
  180. $arguments = $args;
  181. }
  182. $result = call_user_func_array($function, $arguments);
  183. if ($this->onAfterInvoke) {
  184. call_user_func($this->onAfterInvoke, $functionName, $args, $byref, $result);
  185. }
  186. // some service functions/methods may echo content, we need clean it
  187. ob_clean();
  188. if ($resultMode == HproseResultMode::RawWithEndTag) {
  189. $this->output->write($result);
  190. return;
  191. }
  192. elseif ($resultMode == HproseResultMode::Raw) {
  193. $this->output->write($result);
  194. }
  195. else {
  196. $this->output->write(HproseTags::TagResult);
  197. if ($resultMode == HproseResultMode::Serialized) {
  198. $this->output->write($result);
  199. }
  200. else {
  201. $writer->reset();
  202. $writer->serialize($result);
  203. }
  204. if ($byref) {
  205. $this->output->write(HproseTags::TagArgument);
  206. $writer->reset();
  207. $writer->writeList($args);
  208. }
  209. }
  210. } while ($tag == HproseTags::TagCall);
  211. $this->output->write(HproseTags::TagEnd);
  212. ob_end_flush();
  213. }
  214. private function doFunctionList() {
  215. $functions = array_values($this->funcNames);
  216. $writer = new HproseSimpleWriter($this->output);
  217. $this->output->write(HproseTags::TagFunctions);
  218. $writer->writeList($functions);
  219. $this->output->write(HproseTags::TagEnd);
  220. ob_end_flush();
  221. }
  222. private function getDeclaredOnlyMethods($class) {
  223. $all = get_class_methods($class);
  224. if ($parent_class = get_parent_class($class)) {
  225. $inherit = get_class_methods($parent_class);
  226. $result = array_diff($all, $inherit);
  227. }
  228. else {
  229. $result = $all;
  230. }
  231. return $result;
  232. }
  233. public function addMissingFunction($function, $resultMode = HproseResultMode::Normal, $simple = NULL) {
  234. $this->addFunction($function, '*', $resultMode, $simple);
  235. }
  236. public function addFunction($function, $alias = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
  237. if (is_callable($function)) {
  238. if ($alias === NULL) {
  239. if (is_string($function)) {
  240. $alias = $function;
  241. }
  242. else {
  243. $alias = $function[1];
  244. }
  245. }
  246. if (is_string($alias)) {
  247. $aliasName = strtolower($alias);
  248. $this->functions[$aliasName] = $function;
  249. $this->funcNames[$aliasName] = $alias;
  250. $this->resultModes[$aliasName] = $resultMode;
  251. $this->simpleModes[$aliasName] = $simple;
  252. }
  253. else {
  254. throw new HproseException('Argument alias is not a string');
  255. }
  256. }
  257. else {
  258. throw new HproseException('Argument function is not a callable variable');
  259. }
  260. }
  261. public function addFunctions($functions, $aliases = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
  262. $aliases_is_null = ($aliases === NULL);
  263. $count = count($functions);
  264. if (!$aliases_is_null && $count != count($aliases)) {
  265. throw new HproseException('The count of functions is not matched with aliases');
  266. }
  267. for ($i = 0; $i < $count; $i++) {
  268. $function = $functions[$i];
  269. if ($aliases_is_null) {
  270. $this->addFunction($function, NULL, $resultMode, $simple);
  271. }
  272. else {
  273. $this->addFunction($function, $aliases[$i], $resultMode, $simple);
  274. }
  275. }
  276. }
  277. public function addMethod($methodname, $belongto, $alias = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
  278. if ($alias === NULL) {
  279. $alias = $methodname;
  280. }
  281. if (is_string($belongto)) {
  282. $this->addFunction(array($belongto, $methodname), $alias, $resultMode, $simple);
  283. }
  284. else {
  285. $this->addFunction(array(&$belongto, $methodname), $alias, $resultMode, $simple);
  286. }
  287. }
  288. public function addMethods($methods, $belongto, $aliases = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
  289. $aliases_is_null = ($aliases === NULL);
  290. $count = count($methods);
  291. if (is_string($aliases)) {
  292. $aliasPrefix = $aliases;
  293. $aliases = array();
  294. foreach ($methods as $name) {
  295. $aliases[] = $aliasPrefix . '_' . $name;
  296. }
  297. }
  298. if (!$aliases_is_null && $count != count($aliases)) {
  299. throw new HproseException('The count of methods is not matched with aliases');
  300. }
  301. for ($i = 0; $i < $count; $i++) {
  302. $method = $methods[$i];
  303. if (is_string($belongto)) {
  304. $function = array($belongto, $method);
  305. }
  306. else {
  307. $function = array(&$belongto, $method);
  308. }
  309. if ($aliases_is_null) {
  310. $this->addFunction($function, $method, $resultMode, $simple);
  311. }
  312. else {
  313. $this->addFunction($function, $aliases[$i], $resultMode, $simple);
  314. }
  315. }
  316. }
  317. public function addInstanceMethods($object, $class = NULL, $aliasPrefix = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
  318. if ($class === NULL) $class = get_class($object);
  319. $this->addMethods($this->getDeclaredOnlyMethods($class), $object, $aliasPrefix, $resultMode, $simple);
  320. }
  321. public function addClassMethods($class, $execclass = NULL, $aliasPrefix = NULL, $resultMode = HproseResultMode::Normal, $simple = NULL) {
  322. if ($execclass === NULL) $execclass = $class;
  323. $this->addMethods($this->getDeclaredOnlyMethods($class), $execclass, $aliasPrefix, $resultMode, $simple);
  324. }
  325. public function add() {
  326. $args_num = func_num_args();
  327. $args = func_get_args();
  328. switch ($args_num) {
  329. case 1: {
  330. if (is_callable($args[0])) {
  331. return $this->addFunction($args[0]);
  332. }
  333. elseif (is_array($args[0])) {
  334. return $this->addFunctions($args[0]);
  335. }
  336. elseif (is_object($args[0])) {
  337. return $this->addInstanceMethods($args[0]);
  338. }
  339. elseif (is_string($args[0])) {
  340. return $this->addClassMethods($args[0]);
  341. }
  342. break;
  343. }
  344. case 2: {
  345. if (is_callable($args[0]) && is_string($args[1])) {
  346. return $this->addFunction($args[0], $args[1]);
  347. }
  348. elseif (is_string($args[0])) {
  349. if (is_string($args[1]) && !is_callable(array($args[1], $args[0]))) {
  350. if (class_exists($args[1])) {
  351. return $this->addClassMethods($args[0], $args[1]);
  352. }
  353. else {
  354. return $this->addClassMethods($args[0], NULL, $args[1]);
  355. }
  356. }
  357. return $this->addMethod($args[0], $args[1]);
  358. }
  359. elseif (is_array($args[0])) {
  360. if (is_array($args[1])) {
  361. return $this->addFunctions($args[0], $args[1]);
  362. }
  363. else {
  364. return $this->addMethods($args[0], $args[1]);
  365. }
  366. }
  367. elseif (is_object($args[0])) {
  368. return $this->addInstanceMethods($args[0], $args[1]);
  369. }
  370. break;
  371. }
  372. case 3: {
  373. if (is_callable($args[0]) && is_null($args[1]) && is_string($args[2])) {
  374. return $this->addFunction($args[0], $args[2]);
  375. }
  376. elseif (is_string($args[0]) && is_string($args[2])) {
  377. if (is_string($args[1]) && !is_callable(array($args[0], $args[1]))) {
  378. return $this->addClassMethods($args[0], $args[1], $args[2]);
  379. }
  380. else {
  381. return $this->addMethod($args[0], $args[1], $args[2]);
  382. }
  383. }
  384. elseif (is_array($args[0])) {
  385. if (is_null($args[1]) && is_array($args[2])) {
  386. return $this->addFunctions($args[0], $args[2]);
  387. }
  388. else {
  389. return $this->addMethods($args[0], $args[1], $args[2]);
  390. }
  391. }
  392. elseif (is_object($args[0])) {
  393. return $this->addInstanceMethods($args[0], $args[1], $args[2]);
  394. }
  395. break;
  396. }
  397. throw new HproseException('Wrong arguments');
  398. }
  399. }
  400. public function isDebugEnabled() {
  401. return $this->debug;
  402. }
  403. public function setDebugEnabled($enable = true) {
  404. $this->debug = $enable;
  405. }
  406. public function isCrossDomainEnabled() {
  407. return $this->crossDomain;
  408. }
  409. public function setCrossDomainEnabled($enable = true) {
  410. $this->crossDomain = $enable;
  411. }
  412. public function isP3PEnabled() {
  413. return $this->P3P;
  414. }
  415. public function setP3PEnabled($enable = true) {
  416. $this->P3P = $enable;
  417. }
  418. public function isGetEnabled() {
  419. return $this->get;
  420. }
  421. public function setGetEnabled($enable = true) {
  422. $this->get = $enable;
  423. }
  424. public function getFilter() {
  425. return $this->filter;
  426. }
  427. public function setFilter($filter) {
  428. $this->filter = $filter;
  429. }
  430. public function getSimpleMode() {
  431. return $this->simple;
  432. }
  433. public function setSimpleMode($simple = true) {
  434. $this->simple = $simple;
  435. }
  436. public function getErrorTypes() {
  437. return $this->error_types;
  438. }
  439. public function setErrorTypes($error_types) {
  440. $this->error_types = $error_types;
  441. }
  442. public function handle() {
  443. if (!isset($HTTP_RAW_POST_DATA)) $HTTP_RAW_POST_DATA = file_get_contents("php://input");
  444. if ($this->filter) $HTTP_RAW_POST_DATA = $this->filter->inputFilter($HTTP_RAW_POST_DATA);
  445. $this->input = new HproseStringStream($HTTP_RAW_POST_DATA);
  446. $this->output = new HproseFileStream(fopen('php://output', 'wb'));
  447. set_error_handler(array(&$this, '__errorHandler'), $this->error_types);
  448. ob_start(array(&$this, "__filterHandler"));
  449. ob_implicit_flush(0);
  450. ob_clean();
  451. $this->sendHeader();
  452. if (($_SERVER['REQUEST_METHOD'] == 'GET') and $this->get) {
  453. return $this->doFunctionList();
  454. }
  455. elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
  456. try {
  457. switch ($this->input->getc()) {
  458. case HproseTags::TagCall: return $this->doInvoke();
  459. case HproseTags::TagEnd: return $this->doFunctionList();
  460. default: throw new HproseException("Wrong Request: \r\n" . $HTTP_RAW_POST_DATA);
  461. }
  462. }
  463. catch (Exception $e) {
  464. $this->error = $e->getMessage();
  465. if ($this->debug) {
  466. $this->error .= "\nfile: " . $e->getFile() .
  467. "\nline: " . $e->getLine() .
  468. "\ntrace: " . $e->getTraceAsString();
  469. }
  470. $this->sendError();
  471. }
  472. }
  473. $this->input->close();
  474. $this->output->close();
  475. }
  476. public function start() {
  477. $this->handle();
  478. }
  479. }
  480. ?>