bool RPCRequestHandler::executePHPFunction(Transport *transport,
                                           SourceRootInfo &sourceRootInfo) {
  ExecutionContext *context = hphp_context_init();

  // reset timeout counter
  ThreadInfo::s_threadInfo->m_reqInjectionData.started = time(0);

  std::string rpcFunc = transport->getCommand();
  {
    ServerStatsHelper ssh("input");
    RequestURI reqURI(rpcFunc);
    HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo);
    sourceRootInfo.clear();
  }

  bool error = false;

  Array params;
  std::string sparams = transport->getParam("params");
  if (!sparams.empty()) {
    Variant jparams = f_json_decode(String(sparams), true);
    if (jparams.isArray()) {
      params = jparams.toArray();
    } else {
      error = true;
    }
  } else {
    vector<string> sparams;
    transport->getArrayParam("p", sparams);
    if (!sparams.empty()) {
      for (unsigned int i = 0; i < sparams.size(); i++) {
        Variant jparams = f_json_decode(String(sparams[i]), true);
        if (same(jparams, false)) {
          error = true;
          break;
        }
        params.append(jparams);
      }
    } else {
      // single string parameter, used by xbox to avoid any en/decoding
      int size;
      const void *data = transport->getPostData(size);
      if (data && size) {
        params.append(String((char*)data, size, AttachLiteral));
      }
    }
  }

  if (transport->getIntParam("reset") == 1) {
    m_reset = true;
  }
  int output = transport->getIntParam("output");

  int code;
  if (!error) {
    Variant funcRet;
    std::string errorMsg = "Internal Server Error";
    string warmupDoc, reqInitFunc;
    if (m_serverInfo) {
      warmupDoc = m_serverInfo->getWarmupDoc();
      reqInitFunc = m_serverInfo->getReqInitFunc();
    }
    if (warmupDoc.empty()) {
      warmupDoc = RuntimeOption::WarmupDocument;
      reqInitFunc = RuntimeOption::RequestInitFunction;
    }
    warmupDoc = canonicalize_path(warmupDoc, "", 0);
    warmupDoc = get_source_filename(warmupDoc.c_str());
    bool ret = hphp_invoke(context, rpcFunc, true, params, ref(funcRet),
                           warmupDoc, reqInitFunc, error, errorMsg);
    if (ret) {
      String response;
      switch (output) {
      case 0: response = f_json_encode(funcRet);   break;
      case 1: response = context->obGetContents(); break;
      case 2:
        response =
          f_json_encode(CREATE_MAP2("output", context->obGetContents(),
                                    "return", f_json_encode(funcRet)));
        break;
      }
      code = 200;
      transport->sendRaw((void*)response.data(), response.size());
    } else if (error) {
      code = 500;
      transport->sendString(errorMsg, 500);
      m_reset = true;
    } else {
      code = 404;
      transport->sendString("Not Found", 404);
    }
  } else {
    code = 400;
    transport->sendString("Bad Request", 400);
  }
  params.reset();

  transport->onSendEnd();
  ServerStats::LogPage(rpcFunc, code);

  hphp_context_exit(context, true, false);
  return !error;
}