【问题标题】:How to set $_POST values in Node JS child process如何在 Node JS 子进程中设置 $_POST 值
【发布时间】:2017-08-31 03:25:13
【问题描述】:

我在 AWS Lambda 上托管了我的 Slim 应用程序。为了让我的 PHP 应用程序正常工作,我关注了 this tutorial

在我尝试使用 POST 方法提交表单之前,我的应用程序运行良好。我的 PHP 无法从表单中获取值。当我转储 $_POSTfile_get_contents('php://input') 时,都返回了 null

在教程中,Chris(作者)表示,这段代码生成了子进程并设置了一堆环境变量,PHP CGI 将这些环境变量填充到 $_SERVER 超级全局变量中。

var php = spawn('./php-cgi', ['function.php'], {
  env: Object.assign({
      REDIRECT_STATUS: 200,
      REQUEST_METHOD: requestMethod,
      SCRIPT_FILENAME: 'function.php',
      SCRIPT_NAME: '/function.php',
      PATH_INFO: '/',
      SERVER_NAME: serverName,
      SERVER_PROTOCOL: 'HTTP/1.1',
      REQUEST_URI: requestUri
  }, headers)
});

我不熟悉子进程,所以我想问一下是否有办法我也可以填充 $_POST 超全局?因为我认为 POST 数据存在于我的处理函数中的 event 对象/变量中,这意味着(我认为)我的 NodeJS 包装器可以访问 POST 数据,但它没有将其传递给 PHP CGI ?

exports.handler = function(event, context)

这是我的 NodeJS 包装器的完整代码:

var spawn = require('child_process').spawn;

var parseHeaders, parseResponse, parseStatusLine;

parseResponse = function(responseString) {
  var headerLines, line, lines, parsedStatusLine, response;
  response = {};
  lines = responseString.split('\r\n');
  parsedStatusLine = parseStatusLine(lines.shift());
  response['protocolVersion'] = parsedStatusLine['protocol'];
  response['statusCode'] = parsedStatusLine['statusCode'];
  response['statusMessage'] = parsedStatusLine['statusMessage'];
  headerLines = [];
  while (lines.length > 0) {
    line = lines.shift();
    if (line === "") {
      break;
    }
    headerLines.push(line);
  }
  response['headers'] = parseHeaders(headerLines);
  response['body'] = lines.join('\r\n');
  return response;
};

parseHeaders = function(headerLines) {
  var headers, key, line, parts, _i, _len;
  headers = {};
  for (_i = 0, _len = headerLines.length; _i < _len; _i++) {
    line = headerLines[_i];
    parts = line.split(":");
    key = parts.shift();
    headers[key] = parts.join(":").trim();
  }
  return headers;
};

parseStatusLine = function(statusLine) {
  var parsed, parts;
  parts = statusLine.match(/^(.+) ([0-9]{3}) (.*)$/);
  parsed = {};
  if (parts !== null) {
    parsed['protocol'] = parts[1];
    parsed['statusCode'] = parts[2];
    parsed['statusMessage'] = parts[3];
  }
  return parsed;
};

exports.index = function(event, context) {

    // Sets some sane defaults here so that this function doesn't fail when it's not handling a HTTP request from
    // API Gateway.
    var requestMethod = event.httpMethod || 'GET';
    var serverName = event.headers ? event.headers.Host : '';
    var requestUri = event.path || '';
    var headers = {};

    // Convert all headers passed by API Gateway into the correct format for PHP CGI. This means converting a header
    // such as "X-Test" into "HTTP_X-TEST".
    if (event.headers) {
        Object.keys(event.headers).map(function (key) {
            headers['HTTP_' + key.toUpperCase()] = event.headers[key];
        });
    }

    // Spawn the PHP CGI process with a bunch of environment variables that describe the request.
    var php = spawn('./php-cgi', ['slim/public/index.php'], {
        env: Object.assign({
            REDIRECT_STATUS: 200,
            REQUEST_METHOD: requestMethod,
            SCRIPT_FILENAME: 'slim/public/index.php',
            SCRIPT_NAME: '/index.php',
            PATH_INFO: '/',
            SERVER_NAME: serverName,
            SERVER_PROTOCOL: 'HTTP/1.1',
            REQUEST_URI: requestUri
        }, headers)
    });

    // Listen for output on stdout, this is the HTTP response.
    var response = '';
    php.stdout.on('data', function(data) {
        response += data.toString('utf-8');
    });

    // When the process exists, we should have a complete HTTP response to send back to API Gateway.
    php.on('close', function(code) {
        // Parses a raw HTTP response into an object that we can manipulate into the required format.
        var parsedResponse = parseResponse(response);

        // Signals the end of the Lambda function, and passes the provided object back to API Gateway.
        context.succeed({
            statusCode: parsedResponse.statusCode || 200,
            headers: parsedResponse.headers,
            body: parsedResponse.body
        });
    });
};

【问题讨论】:

  • var_dump(file_get_contents('php://input')); 怎么样?
  • 我也试过了。我忘了在我的问题中包括这个。它还返回了一个空值。
  • 尝试将变量作为查询字符串传递? function.php?x=y
  • @OzgurGUL 我认为使用密码不安全?但我可能已经找到了解决方案。我填充了 $_SERVER 超全局元素。 QUERY_STRING 元素。我在那里分配了 event.body 以便我可以访问后端中的值。但我不知道它是否安全或有效。

标签: php node.js amazon-web-services http-post child-process


【解决方案1】:

在某些情况下,需要在环境中设置 CONTENT_LENGTH 和/或 CONTENT_TYPE 以便 php-cgi 正确处理 $_POST。
例如(其中 postBody 是一个类似“field1=value1&field2=value2”的字符串):

var env = {
    'SCRIPT_FILENAME': script_path, 
    'REQUEST_METHOD': 'POST',
    'REDIRECT_STATUS': 1,  
    'CONTENT_TYPE': 'application/x-www-form-urlencoded', 
    'CONTENT_LENGTH': postBody.length  
}

//if the URL has anything after "?", it should appear in $_GET even when the method is "POST"
if(queryString) env['QUERY_STRING'] = queryString; 

帖子正文需要输入到孩子的标准输入中。
这是一个异步示例:

var spawn = require('child_process').spawn; 
var phpProcess = spawn (php_cgi_path, [script_path], {'env': env})
phpProcess.stdin.write( postBody );

var outputBuffer = []; 
phpProcess.stdout.on('data', function(data) { 
    outputBuffer.push (data.toString()); 
}) 
phpProcess.stdout.on('end', function( ) { 
    var phpOutput = outputBuffer.join('') ; 
    // process php output
});

也可以以同步的方式给出输入数据,例如:

var spawnSync = require('child_process').spawnSync; 
var phpProcessSync = spawnSync (php_cgi_path, [script_path], {'env': env, 'input': postBody})
var phpOutput = phpProcessSync.stdout.toString()
// process php output

同样,帖子数据与“env”分开输入。

还可以修改脚本,使其也填充 $_FILES。
例如,可以使用 Uint8Array(而不是字符串)来存储帖子正文,然后将 'CONTENT_TYPE' 设置为 request.headers['content-type']
(然后我们将拥有例如 "Content-Type:multipart/form-data; boundary=----WebKitFormBoundarynGa8p8HMIQ8kWQLA"
然后使用 phpProcess.stdin.write( Buffer.from(postBody) ); 它将在 $_FILES 变量中包含“tmp_name”等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-15
    • 1970-01-01
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    相关资源
    最近更新 更多