Skip to content

Instantly share code, notes, and snippets.

@leeight
Created March 4, 2014 08:38
Show Gist options
  • Save leeight/9342507 to your computer and use it in GitHub Desktop.
Save leeight/9342507 to your computer and use it in GitHub Desktop.
edp-webserver-php-handler
/***************************************************************************
*
* Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved
* $Id$
*
**************************************************************************/
/**
* php.handler.js ~ 2014/02/28 12:07:51
* @author leeight([email protected])
* @version $Revision$
* @description
*
**/
/**
* edp-webserver处理php
*
* 在`edp-webserver-config.js`中配置:
* ```javascript
* {
* location: /^.*$/,
* handler: [
* // 或者直接将php-cgi添加到环境变量中
* php('/usr/local/php/bin/php-cgi')
* ]
* }
* ```
* 调试状态下请打开`php.ini`的`error_reporting`。
*
* @param {?string} handler php-cgi可执行文件路径
*/
module.exports = exports = function(handler, suffix, forwardPathName) {
return function(context) {
var request = context.request;
var targetURL = request.url;
var targetPathName = request.pathname;
// url改换
if (forwardPathName) {
targetPathName = forwardPathName(context);
if (targetPathName) {
targetURL = request.headers.host
+ targetPathName + (request.search || '');
console.log(
'PHP try forwarding request' + (request.url)
+ ' to ' + (targetURL)
);
}
else {
targetPathName = request.pathname;
}
}
suffix = suffix || 'php';
if (!/\.php($|\?)/.test(targetURL)) {
return;
}
// 挂起
context.stop();
console.log(
'PHP request' + (targetURL) + ' | ' + (targetPathName)
);
var path = require('path');
var docRoot = context.conf.documentRoot;
var request = context.request;
var scriptName = targetPathName;
var scriptFileName = path.normalize(
docRoot + targetPathName
);
var query = require('url').parse(request.url).query;
// @see: http://www.cgi101.com/book/ch3/text.html
var host = (request.headers.host || '').split(':');
var env = {
PATH: process.env.PATH,
GATEWAY_INTERFACE: 'CGI/1.1',
SERVER_PROTOCOL: 'HTTP/1.1',
SERVER_ROOT: docRoot,
DOCUMENT_ROOT: docRoot,
SERVER_NAME: host[0],
SERVER_PORT: host[1] || 80,
REDIRECT_STATUS: 200,
SCRIPT_NAME: scriptName, //docroot上的文件
REQUEST_URI: targetURL,
SCRIPT_FILENAME: scriptFileName, //物理文件
REQUEST_METHOD: request.method,
QUERY_STRING: query || ''
};
// expose request headers
for (var header in request.headers) {
var name = 'HTTP_' + header.toUpperCase().replace(/-/g, '_');
env[name] = request.headers[header];
}
if ('content-length' in request.headers) {
env.CONTENT_LENGTH = request.headers['content-length'];
}
if ('content-type' in request.headers) {
env.CONTENT_TYPE = request.headers['content-type'];
}
var child = require('child_process').spawn(
handler || 'php-cgi',
[],
{
env: env
}
);
var bodyBuffer = [];
var isBodyData = false;
var headers = {};
var line = [];
child.on(
'exit',
done
);
child.stderr
.on(
'end',
function () {
console.log('php error end [' + [].slice.call(arguments) + ']');
}
)
.on(
'data',
function () {
console.log('php error data [' + [].slice.call(arguments) + ']');
}
);
child.stdout
.on(
'end',
done
)
.on(
'data',
function(buf) {
for (var i = 0; i < buf.length; i++) {
// 如果是主体数据内容
if (isBodyData) {
return bodyBuffer.push(buf);
}
// 取出header
var c = buf[i];
if (c == 0xA) { // 如果是\n,则一行读取完毕
if (!line.length) { // 如果读取到一个空行
isBodyData = true;
bodyBuffer.push(
buf.slice(i + 1)
);
return;
}
var s = line.join('');
line = [];
var idx = s.indexOf(':');
headers[s.slice(0, idx)] = s.slice(idx + 1).trim();
} else if (c != 0xD) { //如果不是\n,也不是\r,说明一行还未读取结束
line.push(String.fromCharCode(c));
}
}
}
);
// 将php解析后的结果填充到context中
function done(code) {
if (code === undefined) {
return;
}
for(var i in headers) {
if (headers.hasOwnProperty(i)) {
context.header[i] = headers[i];
}
}
context.content = bodyBuffer.join('');
// 如果code非零,也不一定不能运行
// if (code) {
// context.status = 500;
// }
// 标志php成功返回
context.phpOK = true;
context.start();
}
};
};
/* vim: set ts=4 sw=4 sts=4 tw=100: */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment