【问题标题】:PHP/MySQL better user searchingPHP/MySQL 更好的用户搜索
【发布时间】:2017-01-17 01:32:23
【问题描述】:

为了让我在 14 多年前编写的代码恢复活力。我发现我当时编写的可爱的小设置是......在某些地方缺乏,即处理用户输入。

经验教训:永远不要低估用户向验证者注入垃圾、拼写错误和欺骗的能力。

旧方法正在达到临界质量,因为现在 SELECT 下拉列表中有 470 个项目。我想重新发明这部分流程,这样我就不必担心它会达到临界点。

所以想法是建立一个模糊搜索方法,在打字员输入搜索字符串后,我们检查五条数据,所有这些数据都位于同一行。

我需要根据舞台名称、两个也称为名称以及他们的法定名称检查提交的名称,并根据他们的舞台名称对 soundex() 索引进行最后检查(这会捕获一些否则会漏掉拼写错误)

我尝试了一个复杂的代码块来检查这些事情(它不起作用,主要是因为我认为我对比较的编码过于严格)作为 do/while 循环的一部分。

在下面,var $Rin 将包含用户提供的名称。

$setr = mysql_query("SELECT ID,StageName,AKA1,AKA2,LegalName,SoundEx FROM performers");
IF ($R = mysql_fetch_array($setr)) {
    do {
        $RT = substr(trim($Rin), 5);
        $RT1 = substr($R[1], 5);
        $RT2 = substr($R[2], 5);
        $RT3 = substr($R[3], 5);
        $RT4 = substr($R[4], 5);
        $RTx = soundex($RT);
        IF ($RT == $RT1) {
            $RHits[] = $R[0];
        }
        IF ($RT == $RT2) {
            $RHits[] = $R[0];
        }
        IF ($RT == $RT3) {
            $RHits[] = $R[0];
        }
        IF ($RT == $RT4) {
            $RHits[] = $R[0];
        }
        IF ($RTx == $R[5]) {
            $RHits[] = $R[0];
        }
    } while ($R = mysql_fetch_array($setr));
}

我的想法是,我将构建一个 ID# 的近命中数组,我将填充到一个选择下拉列表中,该下拉列表希望只有比整个表格更少的命中。这意味着从该数组的内容中查询结果集,以便在 SELECT 下拉列表中显示执行者的名称并将 ID# 作为这些选项的值传递。

那是当我遇到“我需要在 WHERE 子句中使用数组”问题时,在找到答案后,我开始怀疑由于下面的第 2 条规定我运气不好。所以我开始寻找替代的搜索方法,我不确定我是否得到了任何地方但更加困惑。

那么,有没有更好的方法来扫描单个表的六个字段,根据用户输入检查五个字段并注意第六个字段以显示在原始表的子集中?

思考过程:

针对整个表,每条记录,按以下顺序针对这些测试测试 $Rin:

$Rin -> 舞台名
$Rin -> AKA1
$Rin -> AKA2
$Rin -> 法定姓名
soundex($Rin) -> SoundEx

五个操作中的任何一个命中都会将 ID# 添加到结果数组中,该数组用于将结果从 470 个执行者缩小到可供选择的合理列表。

规定:

1) 正如所写,我知道这很容易受到 SQL 注入攻击。

2) 服务器运行 PHP 4.4.9 和 MySQL 4.0.27-Standard,我无法升级它。在花钱之前,我必须证明它有效。

3) 这是业余爱好,不是我的日常工作。

4) 表演者经常使用非英文名称或名称中的元素,这导致数据输入打字员出现拼写错误和重复。

我已经为这类事情找到了很多 mysqli 和 PDO 答案,而且我看到很多事情只有一半是有意义的(如下面的链接 #4)。在尝试修复损坏的问题时,我正在努力加快处理这些事情的速度。

已经看过的地方:

  1. PHP mysql using an array in WHERE clause
  2. PHP/MySQL small-scale fuzzy search
  3. MySQL SubString Fuzzy Search
  4. Sophisticated Name Lookup

【问题讨论】:

  • 首先,“mysql_”现在已被弃用。请改用“mysqli_”函数。 :)
  • mysqli 在 PHP v4.4.9 上可用吗?
  • 有数百个选项和一个预先输入,我建议在页面加载后通过服务调用 (AJAX) 在后台加载数据,并使用 Javascript 工具处理预先输入,例如Twitter's Typeahead library,尤其是,如果您要搜索多个列。
  • @SandorDosa,您不考虑升级吗?
  • @Ronald 简短回答:是的。长答案更复杂,并且涉及时间压力,以使这个系统至少看起来像它正在运行,而我自学如何再次使用 MySQL 以达到新标准。需要在今年 3 月 10 日前有工作地点。升级可以稍后进行。

标签: php mysql arrays multilingual legacy-code


【解决方案1】:

我在 cmets 中提到 Javascript typeahead 库对您来说可能是一个不错的选择。我发现 Twitter 的 Typeahead 库和 Bloodhound 引擎非常强大。不幸的是,文档参差不齐:只要您需要的内容与他们的示例非常相似,您就可以了,但是缺少某些细节(例如对标记器的解释)。

在 Stack Overflow 上的 several questions re Typeahead 之一中,@JensAKoch 说:

说实话,我认为 twitter 放弃了 typeahead.js。我们查看了 13000 颗星,一个没有维护者的完整 bugtracker 和一个损坏的软件,最后一个版本是 2015 年。我认为这不言自明? ...所以,尝试其中一个分支:github.com/corejavascript/typeahead.js

坦率地说,在简短的检查中,fork 上的文档看起来要好一些,如果没有其他的话。你不妨去看看。

服务器端代码:

使用旧版本 PHP 的所有注意事项均适用。我强烈建议重组以将 PDO 与 PHP 5 一起使用,但此示例按要求使用 PHP 4。

完全未经测试的 PHP 代码。 json_encode() 会更好,但直到 PHP 5 才会出现。您的端点将类似于:

headers("Content-Type: application/json");
$results = mysql_query(
   "SELECT ID,StageName,AKA1,AKA2,LegalName,SoundEx FROM performers"
);

$fields = array("ID","StageName","AKA1","AKA2","LegalName","SoundEx");

echo "[";

$first =  true;
while ($row = mysql_fetch_array($results)) {
    ($first) ? $first = false : echo ',';

    echo "\n\t,{";
    foreach($fields as $f) {
        echo "\n\t\t\"{$f}\": \"".$row[$f]."\"";
    }
    echo "\n\t}";
}
echo "]";

客户端代码:

此示例使用static JSON file 作为所有结果的存根。如果您预计您的结果集将超过 1,000 个条目,您应该查看remote option of Bloodhound。这将需要您编写一些自定义 PHP 代码来处理查询,但它看起来与转储所有(或至少您最常见的)数据的端点非常相似。

var actors = new Bloodhound({
  // Each row is an object, not a single string, so we have to modify the
  // default datum tokenizer. Pass in the list of object fields to be
  // searchable.
  datumTokenizer: Bloodhound.tokenizers.obj.nonword(
    'StageName','AKA1','AKA2','LegalName','SoundEx'
  ),
  queryTokenizer: Bloodhound.tokenizers.whitespace,
  // URL points to a json file that contains an array of actor JSON objects
  // Visit the link to see details 
  prefetch: 'https://gist.githubusercontent.com/tag/81e4450de8eca805f436b72e6d7d1274/raw/792b3376f63f89d86e10e78d387109f0ad7903fd/dummy_actors.json'
});

// passing in `null` for the `options` arguments will result in the default
// options being used
$('#prefetch .typeahead').typeahead(
    {
        highlight: true
    },
   {
        name: 'actors',
        source: actors,
        templates: {
        empty: "<div class=\"empty-message\">No matches found.</div>",
        
        // This is simply a function that accepts an object.
        // You may wish to consider Handlebars instead.
        suggestion: function(obj) {
            return '<div class="actorItem">'
                + '<span class="itemStageName">'+obj.StageName+"</span>"
                + ', <em>legally</em> <span class="itemLegalName">'+obj.LegalName+"</span>"
        }
        //suggestion: Handlebars.compile('<div><strong>{{value}}</strong> – {{year}}</div>')
      },
      display: "LegalName" // name of object key to display when selected
      // Instead of display, you can use the 'displayKey' option too:
      // displayKey: function(actor) {
      //     return actor.LegalName;
      // }
});
/* These class names can me specified in the Typeahead options hash. I use the defaults here. */
    .tt-suggestion {
        border: 1px dotted gray;
        padding: 4px;
        min-width: 100px;
    }
    .tt-cursor {
        background-color: rgb(255,253,189);
    }
    
    /* These classes are used in the suggestion template */
    .itemStageName {
        font-size: 110%;
    }
    .itemLegalName {
        font-size: 110%;
        color: rgb(51,42,206);
    }
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://twitter.github.io/typeahead.js/releases/latest/typeahead.bundle.js"></script>


<p>Type something here. A good search term might be 'C'.</p>
<div id="prefetch">
  <input class="typeahead" type="text" placeholder="Name">
</div>

为方便起见,这里是Gist of the client-side code。

【讨论】:

  • 这看起来是一个可行的解决方案。我不像 PHP 那样精通 javascript。我一定会仔细看看。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-05
  • 2011-04-20
  • 2012-03-11
  • 1970-01-01
相关资源
最近更新 更多