1<?php 2/* 3 +----------------------------------------------------------------------+ 4 | Yar - Light, concurrent RPC framework | 5 +----------------------------------------------------------------------+ 6 | Copyright (c) 2012-2013 The PHP Group | 7 +----------------------------------------------------------------------+ 8 | This source file is subject to version 3.01 of the PHP license, | 9 | that is bundled with this package in the file LICENSE, and is | 10 | available through the world-wide-web at the following url: | 11 | http://www.php.net/license/3_01.txt | 12 | If you did not receive a copy of the PHP license and are unable to | 13 | obtain it through the world-wide-web, please send a note to | 14 | license@php.net so we can mail you a copy immediately. | 15 +----------------------------------------------------------------------+ 16 | Author: Syber <ibar@163.com> | 17 | Xinchen Hui <laruence@php.net> | 18 +----------------------------------------------------------------------+ 19*/ 20 21/*************************************************************************** 22 * 用法:按照正常yar调用方法,只是把类名修改为本调试类名。 23 * 1 24 * $yar = new Yar_Debug_Client('http://yar_server/path'); 25 * var_dump($yar->call('method', $params)); //这里通常能看到server端代码是否有错误,错误在那里。 26 * 2 27 * Yar_Debug_Concurrent_Client::call('http://yar_server/path', 'method', $params, $callback, $errcallback); 28 * Yar_Debug_Concurrent_Client::loop(); //在callback也可以看到server反馈 29 * 30 * 31 * 也可以用这个封装类做一个在线调试 exp: 32 * http://hk.yafdev.com/yar_server_response_viewer.php 33 * 34 * 35***************************************************************************/ 36 37class Yar_Debug_Client { 38 private $url; 39 public function __construct($url) { 40 $this->url = $url; 41 } 42 43 public function call($method, $arguments) { 44 return Yar_Debug_Transports::exec($this->url, Yar_Debug_Protocol::Package($method, $arguments)); 45 } 46 47 public function __call($method, $arguments) { 48 return Yar_Debug_Transports::exec($this->url, Yar_Debug_Protocol::Package($method, $arguments)); 49 } 50} 51 52class Yar_Debug_Concurrent_Client { 53 private static $data = array(); 54 public static function call($uri, $m, $params = null, $callback = null, $errorcallback = null) { 55 $package = Yar_Debug_Protocol::Package($m, $params); 56 self::$data[] = array( 57 'uri' => $uri, 58 'data' => $package, 59 'callback' => $callback, 60 'errcb' => $errorcallback, 61 ); 62 return $package['transaction']; 63 } 64 65 public static function loop() { 66 foreach(self::$data as $v) { 67 $ret = Yar_Debug_Transports::exec($v['uri'], $v['data']); 68 if (strpos('HTTP/1.1 200 OK', $ret['header']) !== false) { 69 $call = $v['callback']; 70 $return = true; 71 } else { 72 $call = $v['errcb']; 73 $return = false; 74 } 75 if (is_callable($call)) { 76 $o = $ret['o']; 77 $r = $ret['r']; 78 call_user_func($call, $r, $o); 79 } 80 } 81 return $return; 82 } 83} 84 85class Yar_Debug_Protocol { 86 public static function Package($m, $params) { 87 $struct = array( 88 'i' => time(), 89 'm' => $m, 90 'p' => $params, 91 ); 92 $body = str_pad('PHP', 8, chr(0)) . serialize($struct); 93 94 $transaction = sprintf('%08x', mt_rand()); 95 96 $header = ''; 97 $header = $transaction; //transaction id 98 $header .= sprintf('%04x', 0); //protocl version 99 $header .= '80DFEC60'; //magic_num, default is: 0x80DFEC60 100 $header .= sprintf('%08x', 0); //reserved 101 $header .= sprintf('%064x', 0); //reqeust from who 102 $header .= sprintf('%064x', 0); //request token, used for authentication 103 $header .= sprintf('%08x', strlen($body)); //request body len 104 105 $data = ''; 106 for($i = 0; $i < strlen($header); $i = $i + 2) 107 $data .= chr(hexdec('0x' . $header[$i] . $header[$i + 1])); 108 $data .= $body; 109 return array( 110 'transaction' => $transaction, 111 'data' => $data 112 ); 113 } 114} 115 116class Yar_Debug_Transports { 117 public static function exec($url, $data) { 118 $urlinfo = parse_url($url); 119 $port = isset($urlinfo["port"])? $urlinfo["port"] : 80; 120 $path = $urlinfo['path'] . (!empty($urlinfo['query']) ? '?' . $urlinfo['query'] : '') . (!empty($urlinfo['fragment']) ? '#' . $urlinfo['fragment'] : ''); 121 122 $in = "POST {$path} HTTP/1.1\r\n"; 123 $in .= "Host: {$urlinfo['host']}\r\n"; 124 $in .= "Content-Type: application/octet-stream\r\n"; 125 $in .= "Connection: Close\r\n"; 126 $in .= "Hostname: {$urlinfo['host']}\r\n"; 127 $in .= "Content-Length: " . strlen($data['data']) . "\r\n\r\n"; 128 129 $address = gethostbyname($urlinfo['host']); 130 131 $fp = fsockopen($address, $port, $err, $errstr); 132 if (!$fp) { 133 die ("cannot conncect to {$address} at port {$port} '{$errstr}'"); 134 } 135 fwrite($fp, $in . $data['data'], strlen($in . $data['data'])); 136 137 $f_out = ''; 138 while ($out = fread($fp, 2048)) 139 $f_out .= $out; 140 141 $tmp = explode("\r\n\r\n", $f_out); 142 return array ( 143 'header' => $tmp[0], 144 'body' => $tmp[1], 145 'return' => unserialize(substr($tmp[1], 82 + 8)), 146 ); 147 fclose($fp); 148 } 149} 150?> 151