1

块引用

我有一个 Web 应用程序(用 js 编写),用户可以在其中输入名称(以及其他条件)并执行对 ML 数据库的搜索,并以表格表示与该名称(或其他搜索条件)关联的一些数据) 被退回。在开发的第一阶段,我编写了 optic api 查询,并将 name 的值硬编码在查询的 where 语句中。我这样做是为了测试 REST api 是否正确调用了查询等。一切正常,我可以看到在 Web 应用程序中返回的硬编码名称的正确结果。现在我想将用户提供的 name 值传递给 Optic api 查询 (EntityInformation_Optic_API_Query.json) 以替换 where 语句中的硬编码值。我该怎么做呢?提前致谢。


所有者编辑

该应用程序是用 PHP 编写的,我在下面复制了代码。在此您可以看到调用 optic api 查询的位置以及构建参数的位置。

<?php
if (!defined('RSS_BASE_URL')) exit;

use MarkLogic\MLPHP as MLPHP;

function rss_api_call($json, $params = array(), $resource = 'rows', $verb = 'POST')
{
    $json = __DIR__ . '/json/' . $json;

    if (!file_exists($json)) return false;

    $request = new MLPHP\RESTRequest('POST', 'rows', $params, file_get_contents($json), array('Content-type' => 'application/json'));
    $response = rss_get_client()->send($request);

    return json_decode($response->getBody());
}

function rss_api_entities()
{
    $params = array();

    return rss_api_call('EntityInformation_Optic_API_Query.json', $params);
    //return (empty($params)) ? '' : rss_api_call('EntityInformation_Optic_API_Query.json', $params);
}

function rss_api_search()
{
    $params = array();

    if (isset($_POST['companyname']) && !empty($_POST['companyname']))
    {
        $params['CompanyName'] = htmlspecialchars($_POST['companyname']);
    }

    if (isset($_POST['EIN']) && !empty($_POST['ein']))
    {
        $params['EIN'] = htmlspecialchars($_POST['ein']);
    }

    if (isset($_POST['city']) && !empty($_POST['city']))
    {
        $params['EntityCity'] = htmlspecialchars($_POST['city']);
    }

    if (isset($_POST['state']) && !empty($_POST['state']))
    {
        $params['EntityState'] = htmlspecialchars($_POST['state']);
    }

    if (isset($_POST['zip']) && !empty($_POST['zip']))
    {
        $params['EntityZip'] = htmlspecialchars($_POST['zip']);
    }

    return rss_api_call('SearchResults_Optic_API_Query.json', $params);
    //return (empty($params)) ? '' : rss_api_call('SearchResults_Optic_API_Query.json', $params);
}

function rss_asset_path($path, $file_name)
{
    global $rss_manifest;

    if (empty($rss_manifest))
    {
        ob_start();

        include(__DIR__ . '/../manifest.json');

        $rss_manifest = json_decode(ob_get_clean(), true);
    }

    if (isset($rss_manifest[$file_name]))
    {
        $file_name = $rss_manifest[$file_name];
    }

    return RSS_ASSET_PATH . $path . '/' . $file_name;
}

function rss_box($title, $content)
{
    echo '<div class="rss-box">' .
        '<div class="rss-box-title">' . $title . '</div>' .
        '<div class="rss-box-content">' . $content . '</div>' .
        '</div>';
}

function rss_get_client()
{
    $mlphp = new MLPHP\MLPHP(array
    (
        'host' => RSS_API_HOST,
        'port' => RSS_API_PORT,
        'version' => RSS_API_VERSION,
        'username' => RSS_API_USERNAME,
        'password' => RSS_API_PASSWORD
    ));

    return $mlphp->getClient();
}

function rss_hidden_search_fields()
{
    echo '<div class="rss-hidden">';

    $fields = array('debug', 'companyname', 'ein', 'city', 'state', 'zip');

    foreach ($fields as $field)
    {
        echo (isset($_POST[$field])) ? '<input name="' . $field . '" type="hidden" value="' . htmlspecialchars($_POST[$field]) . '" />' : '';
    }

    if (!empty($_POST['social']))
    {
        $social = (is_array($_POST['social'])) ? $_POST['social'] : array($_POST['social']);

        foreach ($social as $social_network)
        {
            echo '<input name="social[]" type="hidden" value="' . htmlspecialchars($social_network) . '" />';
        }
    }

    echo (empty($_POST['social-select-all'])) ? '' : '<input name="social-select-all" type="hidden" value="1" />';
    echo '</div>';
}



Part of the EntityInformation_Optic_API_Query.json is below
-----

edit (information from a comment below):

The request will be a POST to /v1/rows. Does the following payload look correct? 

```javascript
{
    "$optic": {
        "ns": "op",
        "fn": "operators",
        "args": [
            {
                "ns": "op",
                "fn": "from-view",
                "args": [ "TestSchema", "SUT", null, null ]
            },
            {
                "ns": "op",
                "fn": "where",
                "args": [
                    {
                        "ns": "op",
                        "fn": "eq",
                        "args": [
                            {
                                "ns": "op",
                                "fn": "col",
                                "args": [ "CompanyName" ]
                            },
                            "${req.params.CompanyName}"
                        ]
                    }
                ]
            }
4

3 回答 3

1

我相信您需要使用“绑定”参数。所以你的计划看起来像这样:

{
  "$optic": {
    "ns": "op",
    "fn": "operators",
    "args": [
      {
        "ns": "op",
        "fn": "from-view",
        "args": [
          "TestSchema",
          "SUT",
          null,
          null
        ]
      },
      {
        "ns": "op",
        "fn": "where",
        "args": [
          {
            "ns": "op",
            "fn": "eq",
            "args": [
              {
                "ns": "op",
                "fn": "col",
                "args": [
                  "CompanyName"
                ]
              },
              {
                "ns": "op",
                "fn": "param",
                "args": [
                  "companyName"
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

然后当您将其发布到 /v1/rows 时,您需要设置companyName绑定参数和类型。因此,将以下参数添加到您的 POST 中:

bind:companyName=${req.params.CompanyName}
bind:companyName:type=xs:string

假设${req.params.CompanyName}包含用户传递的公司名称值。

作为旁注,手动处理序列化的光学计划可能很困难。我建议你把它放在一个 REST 扩展后面,然后传入参数。如果您真的想将光学计划保留在中间层,您始终可以使用 MarkLogic 的查询控制台来生成计划,并op.param()在您想要参数化值的地方进行适当的调用。IE 类似:

const op = require('/MarkLogic/optic');
const plan = op
  .fromView("TestSchema", "SUT")
  .where(
    op.eq(
      op.col("CompanyName"), op.param("companyName")
    )
  )

plan.export()

于 2019-02-28T00:02:48.623 回答
0

这取决于您如何设置应用程序。

REST API

如果您的代码将成为 REST API 扩展,那么您编写的函数将有一个params参数。对于 JavaScript,这将是一个对象。请参阅JavaScript 资源扩展接口。从文档的那一部分:

如果请求是 PUT /v1/resource/my-ext?rs:p=1&rs:p=2,那么 的值为params.p["1", "2"]。

主模块

如果客户端将通过常规(非 REST)主模块访问您的代码,则使用xdmp.getRequestField.


编辑:我用您评论中的更多信息更新了您的问题。在我看来,您有一个中间层,它从客户端(浏览器)获取参数并使用它们来构建查询以传递给/v1/rows. 它看起来像是"${req.params.CompanyName}"要进行插值,以便您的中间层获得 的值req.params.CompanyName,然后将其放入发送到 MarkLogic 的字符串中。

是否有可能"${req.params.CompanyName}"将引号添加到完整的字符串中,从而使中间层无法进行插值?如果您可以提供有关如何/v1/rows构建有效载荷的更多信息,我们也许可以提供更多帮助。

于 2019-02-24T21:08:31.230 回答
0

对于 Java 或 Node.js Web 应用程序,最好的方法可能是编写一个函数来获取值并构建并返回一个光学查询。

在其他环境中,使用 JSON 表示并插入值是最安全的。

通过转义可以将光学查询的 JSON 序列化组装为字符串,但有时难以调试。在 MarkLogic 节点上,JSON 被解析为 JSON 而不是评估,因此不存在注入攻击的风险,但可能会出现解析失败。

希望有帮助,

于 2019-02-25T21:01:57.903 回答