Skip to content

Instantly share code, notes, and snippets.

@forthxu
Created February 13, 2015 09:38
Show Gist options
  • Select an option

  • Save forthxu/aee4a8c15bf55c829c56 to your computer and use it in GitHub Desktop.

Select an option

Save forthxu/aee4a8c15bf55c829c56 to your computer and use it in GitHub Desktop.
PHP开http服务
<?php
trait http{
private $max_read = 8192;
private $software = 'Kws/1.0 (By King)';
private $charset = 'utf-8';
private $headers = [
'_http'=>'HTTP/1.1 %d %s',
'_type'=>'Content-type:%s',
'_time'=>'Date:%s',
'_length'=>'Content-Length:%d',
'_connect'=>'Connection:keep-alive',
'_sorfware'=>'Server:%s'
];
private $status = [
// Informational 1xx
100 => 'Continue',
101 => 'Switching Protocols',
// Success 2xx
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
// Redirection 3xx
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found', // 1.1
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
// 306 is deprecated but reserved
307 => 'Temporary Redirect',
// Client Error 4xx
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
// Server Error 5xx
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported',
509 => 'Bandwidth Limit Exceeded'
];
private $server = [];
//socket 套接字
private $socket;
//accept
private $accept;
//绑定端口
private $ip;
//callback
private $call;
//end header
private $crlf = "\r\n\r\n";
//html
private $html = [];
//request
private $request = [];
function bind($ip,$port,$type='tcp'){
$this->server['ip'] = $ip;
$this->server['port'] = $port;
$stype = sprintf('%s://%s:%d',$type,$ip,$port);
$this->socket = stream_socket_server($stype,$error,$errno);
if($this->socket) return true;
if(!$this->socket) return false;
}
function accept(){
$this->accept = @stream_socket_accept($this->socket,-1,$this->ip);
stream_set_blocking($this->socket,0);
if($this->accept !== false) return true;
}
function close(){
if($this->accept) {
@fclose($this->accept);
}
}
function sendReplys(){
$headers = [];
$pre = headers_list();
foreach($pre as $key=>$value){
if(strpos(strtolower($value),'content-type')===0){
unset($pre[$key]);
$type = substr($value,strpos($value,':')+1,strlen($value));
}
}
if(!empty($type)){
$headers['type'] = $type;
}else{
$headers['type'] = sprintf('text/html;charset=%s',$this->charset);
}
$body = !empty($this->html) ? join(null,$this->html) : null;
$headers['status'] = http_response_code();
$this->server['headers'][] = sprintf($this->headers['_http'],$headers['status'],$this->status[$headers['status']]);
$this->server['headers'][] = sprintf($this->headers['_type'],$headers['type']);
$this->server['headers'][] =sprintf($this->headers['_time'],gmdate("D, d M Y H:i:s T"));
$this->server['headers'][] =sprintf($this->headers['_length'],strlen($body));
$this->server['headers'][] = $this->headers['_connect'];
$this->server['headers'][] = sprintf($this->headers['_sorfware'],$this->software);
$end = array_pop($this->server['headers']);
$this->server['headers'] = array_merge($this->server['headers'],$pre);
array_push($this->server['headers'],$end);
$str = join("\r\n",$this->server['headers']).$this->crlf;
fputs($this->accept,$str,strlen($str));
if(!empty($this->html)) fputs($this->accept,$body,strlen($body));
}
function work(){
ob_start();
$this->run();
$app = ob_get_clean();
$this->send($app);
}
function send($data=null){
$this->html[] = $data;
}
function request(){
$uri = fread($this->accept,$this->max_read);
$request = explode("\r\n", $uri);
$this->request['_uri'] = array_shift($request);
foreach ($request as $key => $value) {
if(strpos($value,":")){
$name = sprintf('HTTP_%s',str_replace('-','_',strtoupper(substr($value,0,strpos($value,":")))));
$this->request[$name] = substr($value,strpos($value,':')+1,strlen($value));
}
}
$post = explode(" ", $uri)[0];
if($post=='POST') {
//post处理
$this->server['post'] = end($request);
}
}
function php_server(){
unset($_SERVER,$_REQUEST,$_GET,$_POST);
$ip = explode(":",$this->ip);
$request_uri = explode(' ',$this->request['_uri'])[1];
$path = parse_url($request_uri);
$this->server['query'] = isset($path['query']) ? $path['query'] : null;
$SERVER["DOCUMENT_ROOT"] = dirname(__FILE__);
$SERVER['REMOTE_ADDR'] = $ip[0];
$SERVER["REMOTE_PORT"] = $ip[1];
$SERVER["SERVER_NAME"] = $this->server['ip'];
$SERVER["REQUEST_URI"] = $request_uri;
$SERVER["QUERY_STRING"] = $this->server['query'];
$SERVER["SCRIPT_NAME"] = basename(__FILE__);
$SERVER["PHP_SELF"] = __FILE__;
$SERVER["SCRIPT_FILENAME"] = __FILE__;
$SERVER["SERVER_PORT"] = $this->server['port'];
$SERVER["SERVER_SOFTWARE"] = $this->software;
$SERVER["SERVER_PROTOCOL"] = explode(' ', $this->request['_uri'])[2];
$SERVER["REQUEST_METHOD"] = explode(' ', $this->request['_uri'])[0];
$SERVER["REQUEST_TIME_FLOAT"] = gettimeofday(true);
$SERVER["REQUEST_TIME"] = time();
$_SERVER = array_merge($SERVER,$this->request);
unset($_SERVER['_uri']);
}
function php_cookie(){
if(empty($this->request['HTTP_COOKIE'])) return;
$_COOKIE=[];
$cookie = explode(';',$this->request['HTTP_COOKIE']);
foreach ($cookie as $key => $value) {
if(!strpos($value,'=')) return;
$_COOKIE[trim(substr($value,0,strpos($value,'=')),' ')] = urldecode(substr($value,strpos($value,'=')+1,strlen($value)));
}
$_COOKIE = array_merge([],$_COOKIE);
}
function php_get(){
if(empty($this->server['query'])) return;
$_GET = [];
$get = explode('&',$this->server['query']);
foreach ($get as $key => $value) {
if(!strpos($value,'=')) return;
$_GET[trim(substr($value,0,strpos($value,'=')),' ')] = urldecode(substr($value,strpos($value,'=')+1,strlen($value)));
}
$_REQUEST = $_GET;
}
function php_post(){
if(empty($this->server['post'])) return;
$_POST = [];
$get = explode('&',$this->server['post']);
foreach ($get as $key => $value) {
if(!strpos($value,'=')) return;
$_POST[trim(substr($value,0,strpos($value,'=')),' ')] = urldecode(substr($value,strpos($value,'=')+1,strlen($value)));
}
$_REQUEST = $_POST;
}
function php_handler(){
//php server 支持
$this->php_server();
//php cookie 支持
$this->php_cookie();
//php get 支持
$this->php_get();
//php post 支持
$this->php_post();
}
private function start(){
//解析request
$this->request();
$this->php_handler();
/**user**/
$this->work();
/**end*/
$this->sendReplys();
}
function dispatch(){
while(true){
usleep(1);
$this->accept();
$pid = pcntl_fork();
if($pid==-1){
exit('create pcntl faild!');
}elseif($pid){
$this->start();
break;
}
$this->close();
}
}
}
if(version_compare(PHP_VERSION, '5.4.0', '<'))
die('php版本小于5.4不支持');
if(substr(strtolower(PHP_OS),0,3)=='win' || substr(strtolower(PHP_SAPI),0,3)!=='cgi')
die('请在linux下用cgi方式运行~');
if(!extension_loaded('pcntl'))
die('需要安装pcntl拓展');
/**
* expmple
*/
class server{
use http;
function run(){
//要工作的php代码~
phpinfo();
}
}
$http = new server;
$http->bind('0.0.0.0',1131);
$http->dispatch();
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment