【问题标题】:Retrieve MYSQL field array with "Like"使用“Like”检索 MYSQL 字段数组
【发布时间】:2013-07-14 04:49:05
【问题描述】:

我将页面保存在 mysql db 中,其中一个字段是每个页面的标签数组,希望对站点搜索有所帮助。

我收到一个由我的电话引起的错误...

$results = $db->select('pages','','','name',array('name', 'DESC'),'10',array('tags', '%' .$word. '%'));

(select的作用是——'table','where','bind for where query match','fields','orderby array','limit',where/like array')

我认为问题在于“标签”字段是一个数组。解决此问题的最佳方法是什么?如有必要,我会在查询后将每个结果都提取出来:

//if we got something through $_POST
if (isset($_GET['search'])) {
// here you would normally include some database connection
require_once('../config/dbconfig.php');

// never trust what user wrote! We must ALWAYS sanitize user input
//$word = mysql_real_escape_string($_POST['search']);
$word = htmlentities($_GET['search']);
// build your search query to the database
//$sql = "SELECT title, url FROM pages WHERE content LIKE '%" . $word . "%' ORDER BY title LIMIT 10";

$results = $db->select('pages','','','*',array('name', 'DESC'),'10',array('tags', '%' .$word. '%'));

// get results
if (count($results) > 0) {
    $end_result = '';
    echo '<ul>';
    foreach($results as $row) {
        $bold = '<span class="found">' .$word. '</span>';
        $end_result .= '<li>' .str_ireplace($word, $bold, $row['title']).   '</li>';
    }
    //echo $end_result. '</ul>';
}else {
    //echo '<ul><li>No results found</li></ul>';
}
var_dump($results);
exit;
}

它说错误在我的 foreach 中:

警告:为 foreach() 提供的参数无效

到目前为止,每次都是因为我之前的查询。每一次。

我搜索并没有看到任何类似的东西,如果我错过了,我很抱歉。我也累了,所以如果我错过了一些细节,请告诉我,我会发布它们。谢谢!

这是选择在运行之前的处理方式。

public function select($table, $where="", $bind="", $fields="*", $order="", $limit="", $like="") {
    $sql = "SELECT " . $fields . " FROM " . $table;
    if(!empty($where)) {
        $sql .= " WHERE " . $where;
    }
    if (!empty($order)) {
        $sql .= " ORDER BY " . $order[0] . " " . $order[1];
    }
    if (!empty($limit) && is_array($limit)) {
        $sql .= " LIMIT " . $limit[0] . " " . $limit[1];
    }
    if (!empty($limit)) {
        $sql .= " LIMIT " . $limit;
    }
    if (!empty($like)) {
        $sql .= " WHERE " .$like[0]. " LIKE " . $like[1];
    }
    $sql .= ";";
    //var_dump($sql);
    //var_dump($bind);
    //exit;
    return $this->run($sql, $bind);
}

public function run($sql, $bind="") {
    $this->sql = trim($sql);
    $this->bind = $this->cleanup($bind);
    $this->error = "";

    try {
        $pdostmt = $this->prepare($this->sql);
        if($pdostmt->execute($this->bind) !== false) {
            if(preg_match("/^(" . implode("|", array("select", "describe", "pragma")) . ") /i", $this->sql))
                return $pdostmt->fetchAll(PDO::FETCH_ASSOC);
            elseif(preg_match("/^(" . implode("|", array("delete", "insert", "update")) . ") /i", $this->sql))
                return $pdostmt->rowCount();
        }   
    } catch (PDOException $e) {
        $this->error = $e->getMessage();    
        $this->debug();
        return false;
    }
}

(切换到 $_GET b/c 搜索正在使用 AJAX,并且不想更改一堆东西只是为了调用它,所以直接在带有 url 的页面中进行。)

关于我刚刚删除的那个查询编辑的纳米,第一次是对的......累对不起......

【问题讨论】:

  • 标签字段是一个数组是什么意思?数组在 MySQL 中不是有效的列类型。
  • 另外,$db 是什么类型的对象?我不熟悉具有 select() 这样的方法的任何东西。
  • 术语可能是错误的,我正在使用的表中的一个字段示例,名为“标签”,值是:“关于,任务,什么,是,imengine,工作室”。我想它实际上只是一个带有 cmets 的字符串。 $db 是用来启动与数据库的连接的对象。使用非常讨厌的包装器来保持连接。它适用于我的许多其他查询。
  • 我确信$db 可以正常工作,但问题在于传递给select() 的参数或它返回的对象——这两个我都不熟悉。如果是您自己的对象,您能否提供更多详细信息?
  • 如果你在select() 通话后var_dump($results) 会得到什么?

标签: php mysql foreach sql-like


【解决方案1】:

一个问题是您在非数组值上使用count()

当一个非数组转换为一个数组时,它变成一个包含原始值的单元素数组。

(array) 1234; // results in array(0 => 1234)
(array) "ABC" // results in array(0 => "ABC")
(array) false // results in array(0 => false)

因此,当您执行count($results)$resultsfalse 时,该值将在内部转换为数组,您将获得1,因为它是一个单元素数组 - 以及您的代码处理结果将运行而不是 else 子句。

这就是导致您看到的 Invalid argument supplied for foreach() 错误消息的原因。


至于为什么它首先返回 false,让我们看一下正在生成的查询:

SELECT name FROM pages ORDER BY name DESC WHERE tags LIKE %someword%

这里实际上有几个问题:

  1. 您的单词值没有被引用。所以查询将结束于:

    WHERE tags LIKE %someword%
    

    所以一个错误是由%someword% 周围缺少引号引起的。

    我猜这应该是 select() 函数的责任 - 以及转义值以防止 SQL 注入,这也是缺失的。

    最好的解决方案可能是让$like 参数自动使用?,并添加到$bind 值。我假设$bind 只是一个数组,所以你可以这样做:

    if (!empty($like)) {
        if (empty($bind)) $bind = array();
        $bind[] = $like[1];
        $sql .= " WHERE " .$like[0]. " LIKE ?"
    }
    
  2. LIKE 条件被添加到查询的末尾 - 在任何 ORDER BYLIMIT 子句之后。这也会导致无效的 SQL。如果$like需要额外的参数,应该和现有的$where条件同时处理,而不是在order-by之后。

总的来说,我不明白您为什么要为 $like 使用第 7 个参数,而不是将 "tags LIKE ?" 传递给现有的 $where 参数。


与其猜测导致它返回 false 的错误是什么,不如直接看看实际的错误消息?

您在返回 false 之前保存了错误消息...因此,如果您将其添加到 if 条件的开头:

if ($results === false) {
    echo($db->error);
} elseif (count($results) > 0) {

...您应该能够确切地看到 PDO 抱怨的内容。

【讨论】:

  • 感谢您指出这一点,因为我以后会遇到问题。 :) 没想到,将搜索更改为包含我知道会返回多个的内容,并更改为仅提取所有记录,而不仅仅是“名称”,但仍然没有。
  • 为like 添加了额外的东西,但结果相同。老实说,这是一个很好的观点,我不知道为什么我不把它放在 WHERE 中大声笑,无论哪种方式仍然会遇到同样的问题。还为查询添加了 OP 中代码的运行部分,但我认为它不是包装器,因为它在新闻系统、登录/注销/注册、加载/编辑/添加页面等方面工作良好. 这个查询中的一些具体内容与具有“a、b、c、d”的记录有关,我仍然认为,只是不知道是什么,因为我以前从未这样做过。
  • 哦,男孩...不,这解决了它。我真的很抱歉,但非常感谢你!不敢相信我错过了。
  • @Grant 很高兴我们能够帮助解决这个问题。我建议做一些事情来显示实际的 PDO 错误消息和可能的实际查询字符串,以帮助将来跟踪此类事情。目前,您似乎正在返回 false 并且没有在任何地方显示错误消息。
  • 是的,我刚刚把这个备份了。它在我的待办事项清单上。不过,我真的应该先做...有点愚蠢,哈哈。
猜你喜欢
  • 1970-01-01
  • 2018-10-24
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 1970-01-01
  • 1970-01-01
  • 2021-09-22
  • 1970-01-01
相关资源
最近更新 更多