UNPKG

edp-webserver

Version:
215 lines (172 loc) 6.34 kB
/*************************************************************************** * * Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved * $Id$ * **************************************************************************/ /** * php.handler.js ~ 2014/02/28 12:07:51 * @author leeight(liyubei@baidu.com) * @version $Revision$ * @description * **/ var edp = require( 'edp-core' ); /* jshint camelcase: false */ /** * 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=} opt_handler php-cgi可执行文件路径 * @param {string=} opt_suffix 后缀名. * @param {function(Object):string=} opt_forwardPathName url转化的函数. */ module.exports = exports = function(opt_handler, opt_suffix, opt_forwardPathName) { var handler = opt_handler || 'php-cgi'; // var suffix = opt_suffix || 'php'; return function(context) { var request = context.request; var targetURL = request.url; var targetPathName = request.pathname; var targetSearch = request.search; // url改换 if ( opt_forwardPathName ) { var changed = opt_forwardPathName(context); if (changed) { targetPathName = changed.pathname || targetPathName; targetSearch = changed.search || targetSearch; targetURL = request.headers.host + targetPathName + targetSearch; edp.log.info( 'PHP try forwarding request' + (request.url) + ' to ' + (targetURL) ); } } if (!/\.php($|\?)/.test(targetURL)) { return; } // 挂起 context.stop(); edp.log.info( '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 = null; if (targetSearch) { query = require('url').parse(targetSearch).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 || '', TRANSFER_ENCODING: 'Chunked' }; // 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 || request.method === 'POST' || request.method === 'PUT') { // env.CONTENT_LENGTH = getContentLength(request); // console.log(env.CONTENT_LENGTH); // } if ('content-type' in request.headers) { env.CONTENT_TYPE = request.headers['content-type']; } var child = require('child_process').spawn( handler, [], { env: env } ); var bodyBuffer = []; var isBodyData = false; var headers = {}; var line = []; child.on( 'exit', done ); child.on('error', function () { edp.log.error('php error [' + [].slice.call(arguments) + ']'); }); child.stderr .on( 'end', function (chunk) { chunk && edp.log.error('php error:\n' + chunk.toString('utf8') + '\n'); }) .on( 'data', function (chunk) { chunk && edp.log.error('php error:\n' + chunk.toString('utf8') + '\n'); }); 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.toLowerCase()] = 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: */