简体   繁体   English

PHP / Mysql:数组而不是stdClass对象

[英]PHP/Mysql: Array instead of stdClass Object

I have the below code: 我有以下代码:

$result = $conn->query($sql)->fetch(PDO::FETCH_COLUMN);
$myArray = explode(',', $result);
$sql = ("SELECT username,status,location FROM Users WHERE username IN ('"    . implode("','",$myArray) . "') AND status > 0 ORDER BY username");
$data = $conn->query($sql)->fetchAll(PDO::FETCH_OBJ);
print_r ($data);

FYI $result is "kk,bb" 仅供参考,结果是“ kk,bb”

The output is as follows: 输出如下:

Array ( [0] => stdClass Object ( [username] => bb [status] => 1   [location] => ) [1] => stdClass Object ( [username] => kk [status] => 1   [location] => ) )

But I really just want to see a two-dimensional array without it saying stdClass Object in front of each item. 但是我真的只想看到一个二维数组,而不必在每个项目前面都说stdClass对象。 I tried different kinds of fetching, but this is the only one I could make work. 我尝试了各种提取,但这是我唯一可以进行的工作。 I know there are functions for converting object to array, but I´d rather if there´sa way to do this right, if there is such a thing, in the pasted code. 我知道有一些将对象转换为数组的函数,但是我希望在粘贴的代码中是否有一种正确的方法,如果有的话。

I hope someone can help, thanks in advance! 希望有人能提供帮助,在此先感谢!

You requested objects by using PDO::FETCH_OBJECT . 您通过使用PDO::FETCH_OBJECT请求对象。 If you want to fetch as arrays, use another fetch type: 如果要以数组形式获取,请使用另一种获取类型:

$data = $conn->query($sql)->fetchAll(PDO::FETCH_ASSOC);

or 要么

$data = $conn->query($sql)->fetchAll(PDO::FETCH_NUM);

The other choices are documented here: http://php.net/manual/en/pdostatement.fetch.php 其他选择记录在这里: http : //php.net/manual/en/pdostatement.fetch.php

By the way, why do you run one query to get the values in $myArray , then use these in an SQL-injection vulnerable way in a second query? 顺便说一句,为什么要运行一个查询以获取$myArray的值,然后在第二个查询中以SQL注入易受攻击的方式使用它们? Wouldn't it be easier to use a JOIN ? 使用JOIN会更容易吗?


Re your comment: 发表您的评论:

Fist of all, I strongly urge you to code safely the first time, don't rely on "going back later." 首先,我强烈建议您第一次安全编写代码,不要依赖“稍后再返回”。 You probably won't have time to go back later, because once the code seems to work "good enough," the temptation is to go live immediately. 您可能没有时间再回头,因为一旦代码看起来“足够好”,那么诱惑就是立即生效。 Even if you do go back later to fix security flaws, you might miss one. 即使您稍后再解决安全漏洞,也可能会错过一个。 Either way, your development process creates a high risk that you will go live with insecure code. 无论哪种方式,您的开发过程都会带来很高的风险,即您将无法使用不安全的代码。

A piece of old advice from famous computer scientist Andrew S. Tanenbaum: "Security, like correctness, is not an add-on feature." 著名计算机科学家Andrew S. Tanenbaum提出的一条旧建议:“安全性(如正确性)不是附加功能。”

Now about joins. 现在关于联接。 If you use SQL, you should understand how to do a joins. 如果使用SQL,则应了解如何进行联接。 Not knowing joins in SQL is like thinking you know PHP even though you don't know how to use foreach() . 即使您不知道如何使用foreach()也不知道SQL中的联接就像认为您了解PHP。 Technically, you can still do some stuff, but you're missing out on a major part of the language. 从技术上讲,您仍然可以做一些事情,但是您错过了该语言的主要部分。

Joins allow you to query multiple tables in one query, and find rows from each table that match. 联接使您可以在一个查询中查询多个表,并从每个表中查找匹配的行。

In your example, I don't know your first query, but I'll take a guess that it queries some other table to get a list of usernames. 在您的示例中,我不知道您的第一个查询,但是我猜想它会查询其他表以获取用户名列表。 Maybe it queries a list of users who are recipients of a email, like this: 也许它查询电子邮件收件人的用户列表,如下所示:

SELECT username FROM EmailRecipients WHERE EmailId = 1234

Then your code uses the result list of usernames in a second query. 然后,您的代码在第二个查询中使用用户名的结果列表。 But you can do it all in one query: 但是您可以在一个查询中完成所有操作:

SELECT Users.username, Users.status, Users.location
FROM Users JOIN EmailRecipients 
  ON Users.username = EmailRecipients.username
WHERE EmailRecipients.EmailId = 1234

The SQL engine searches the EmailRecipients table and say it finds six rows for the recipients of email 1234. For each of the six rows, it looks up the corresponding row in the Users table with the matching username. SQL引擎搜索EmailRecipients表,并说它找到六行作为电子邮件1234的收件人。对于这六行中的每行,它将在Users表中查找具有匹配用户名的对应行。 Then it uses columns from those rows in the SELECT result. 然后,它将使用SELECT结果中这些行中的列。

When you join tables, there's a possibility both tables might have some columns with the same name. 当您联接表时,两个表可能都有一些具有相同名称的列。 That's why I showed column named by qualifying them as belonging to one table or the other. 这就是为什么我显示列的原因是它们限定为属于一个表或另一个表。 This removes the ambiguity about which table you meant in each case. 这样就消除了每种情况下您要使用的表的歧义。

It doesn't matter which table you list first. 首先列出哪个表都没有关系。 This type of join is the same left-to-right as it is right-to-level, like some expressions in algebra (2 + 4 is the same as 4 + 2, etc.). 这种连接类型从左到右与从右到高层相同,就像代数中的某些表达式一样(2 + 4与4 + 2相同,依此类推)。 MySQL automatically figures out which table is most efficient to read first. MySQL自动找出最先读取哪个表最有效。

There's more to learn about joins, but that should get you started. 还有更多有关联接的知识,但这应该可以帮助您入门。 I suggest you pick up a tutorial or a book on SQL sometime. 我建议您有时选择有关SQL的教程或书籍。


Re your comment: 发表您的评论:

Where is the "SQL-injection vulnerable way in a second query"? “第二个查询中的SQL注入易受攻击的方式”在哪里?

In your code: 在您的代码中:

$result = $conn->query($sql)->fetch(PDO::FETCH_COLUMN); $ result = $ conn-> query($ sql)-> fetch(PDO :: FETCH_COLUMN); $myArray = explode(',', $result); $ myArray = explode(',',$ result); $sql = ("SELECT username,status,location FROM Users WHERE username IN ('" . implode("','",$myArray) . "') AND status > 0 ORDER BY username"); $ sql =(“ SELECT username,status,location from users where where username username in('”。implode(“','”,$ myArray)。“')AND status> 0 ORDER BY username”); $data = $conn->query($sql)->fetchAll(PDO::FETCH_OBJ); $ data = $ conn->查询($ sql)-> fetchAll(PDO :: FETCH_OBJ);

There's no guarantee that the elements in $myArray are safe to use in an SQL statement. 不能保证$ myArray中的元素可以在SQL语句中安全使用。 Just because they came out of the database doesn't make them safe. 仅仅因为它们来自数据库并不能保证它们的安全。 What if they contain names like "O'Reilly"? 如果它们包含“ O'Reilly”之类的名称怎么办? That will upset your quote-implosion. 那会打乱您的报价内爆。

You can never be 100% sure the data is safe, so it's better to use query parameters . 您永远不能百分百确定数据是安全的,因此最好使用查询参数 Then you don't care if it's safe, because bound parameters are never combined with the SQL query string. 然后,您不必在意它是否安全,因为绑定参数永远不会与SQL查询字符串组合在一起。

Here's how to create a dynamic list for the IN ( ) predicate from an array, and bind parameter values to the query using PDO: 以下是从数组为IN ( )谓词创建动态列表,以及使用PDO将参数值绑定到查询的方法:

$result = $conn->query($sql)->fetch(PDO::FETCH_COLUMN);
$myArray = explode(',', $result);
$placeholders = implode(',', array_fill(0, count($myArray), '?'));
$sql = "
  SELECT username,status,location FROM Users 
  WHERE username IN ($placeholders) AND status > 0 
  ORDER BY username");
$stmt = $conn->prepare($sql);
$stmt->execute($myArray);
$data = $stmt->fetchAll(PDO::FETCH_OBJ);

While both answers are perfectly valid, I just wanted to add in that there is another solution to your issue. 虽然两个答案都完全有效,但我只是想补充一点,您的问题还有另一种解决方案。

You can change the default fetch style by defining it where you connect to the database: 您可以通过在连接数据库的位置定义默认的访存样式来更改它:

$host = 'localhost';
$user = 'user';
$pass = 'pass';
$mydb = 'mydbname';

$conn = new PDO("mysql:host=$host;dbname=$mydb", $user, $pass, [
  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

Or you can change it by using setAttribute() using the existing connection: 或者,您可以使用现有连接使用setAttribute()来更改它:

$conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

Then you can simply use: 然后,您可以简单地使用:

$conn->query($sql)->fetchAll();

And you still have the ability to overwrite the default value: 而且您仍然可以覆盖默认值:

$conn->query($sql)->fetchAll(PDO::FETCH_NUM);

using PDO::FETCH_ASSOC you can make it as an array. 使用PDO::FETCH_ASSOC可以将其设置为数组。 So 所以

$data = $conn->query($sql)->fetchAll(PDO::FETCH_ASSOC);

Documentation link: 文档链接:

PDO Statement PDO声明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM