0

我对这个查询有疑问,希望有人能帮我解决这个问题。在我的网站注册新用户时,我正在尝试检查用户名和电子邮件地址是否可以注册。用户名来自登录表,电子邮件地址来自联系人表。现在我需要进行查询以检查新用户的给定用户名和电子邮件是否可以注册。如果这些不可用,我想打印错误消息。我正在尝试使这个查询像这样,但它没有按我预期的那样工作。

$q = "SELECT username, email FROM login 
      INNER JOIN contact 
      WHERE login.username = '$username' OR contact.email = '$email'";

然后我像这样在PHP中检查这个查询

$r = mysqli_query ($dbc, $q);

// Get the number of rows returned:
$rows = mysqli_num_rows($r);

if ($rows == 0) { // No problems!

   // register new user 

} else { // The email address or username is not available.

    if ($rows == 2) { // Both are taken.

    $reg_errors['email'] = 'This email address has already been registered.1';          
    $reg_errors['username'] = 'This username has already been registered.2';            

    } else { // One or both may be taken.

                // Get row:
                $row = mysqli_fetch_array($r, MYSQLI_NUM);

                if( ($row[0] == $_POST['email']) && ($row[1] == $_POST['username'])) { // Both match.
                    $reg_errors['email'] = 'This email address has already been registered.3';  
                    $reg_errors['username'] = 'This username has already been registered with this email address.4';
                } elseif ($row[0] == $_POST['email']) { // Email match.
                    $reg_errors['email'] = 'This email address has already been registered.5';                      
                } elseif ($row[1] == $_POST['username']) { // Username match.
                    $reg_errors['username'] = 'This username has already been registered.6';            
                }

} // End of $rows == 2 ELSE.

我的问题是 PHP 脚本总是去这个代码。查询不单独检查用户名和电子邮件。我尝试这样的事情..用户名不可用且电子邮件可用,电子邮件不可用且用户名可用。但总是去这个

if ($rows == 2) { // Both are taken.

$reg_errors['email'] = 'This email address has already been registered.1';          
$reg_errors['username'] = 'This username has already been registered.2';            

}

编辑:表结构..

# --------------
# Login Table 
# --------------

CREATE TABLE login (
login_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(80) NOT NULL, 
password VARBINARY(32) NOT NULL,
PRIMARY KEY (login_id),
UNIQUE(username) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

# --------------
# Contact Table
# --------------

CREATE TABLE contact (
contact_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
telephone VARCHAR(60) DEFAULT NULL, 
mobile CHAR(10) NOT NULL, 
email VARCHAR(80) DEFAULT NULL, 
PRIMARY KEY (contact_id),
UNIQUE (email)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
4

5 回答 5

3

目前,只要其中一个或另一个有一个匹配项,您的查询就会从两个表中选择每一行。您可以同时从两个表中获取匹配的行:

SELECT username FROM login WHERE username = '$username'
UNION ALL SELECT email FROM contact WHERE email = '$email'

...以及单独的查询。

您的查询容易受到 SQL 注入的攻击。

于 2013-01-31T14:19:09.363 回答
3

您必须提供ON定义两个表如何相互关联的关系的子句。

SELECT  username, email 
FROM    login 
        INNER JOIN contact 
            ON login.colname = b.colName  // change to your orignal colName
WHERE   login.username = '$username' OR 
        contact.email = '$email'

作为旁注,SQL Injection如果变量的值(s)来自外部,则查询很容易受到攻击。请看下面的文章,了解如何预防。通过使用PreparedStatements,您可以摆脱在值周围使用单引号。

在不检查表上的值的情况下执行此操作的另一种方法是对表的UNIQUE列强制执行约束,例如

ALTER TABLE login ADD CONSTRAINT tb_uq UNIQUE (username);
ALTER TABLE contact ADD CONSTRAINT tb_uq1 UNIQUE (email);

成功执行两个 alter 语句后,如果该列上已存在值,则无法插入该值。

更新 1

SELECT COUNT(*)
FROM
(
   SELECT userName as Value FROM Login
   UNION
   SELECT email as Value FROM contact
) s
WHERE VALUE IN ('$username','$email')

如果上面的查询将返回大于 0,则表示值已经存在。

更新 2

SELECT *
FROM
(
   SELECT userName, NULL AS email FROM Login
   UNION
   SELECT NULL AS username, email FROM contact
) s
WHERE username = '$username' OR email = '$email'
于 2013-01-31T14:19:52.733 回答
2

你真的在检查两件不同的事情。单个查询没有意义,至少不是join. 我建议union

select 'username' as exists from login 
    where username = '$username'
union all
select 'email' as exists from contact
    where email = '$email'

这将返回一个表,其中包含一个名为exists的列和每个存在的元素的行。如果用户名和电子邮件都存在,您会得到以下信息:

EXISTS
username
email

在您运行此查询的地方,您已经知道他们输入的用户名和电子邮件是什么,因此从表中返回这些值是没有意义的。

正如其他人所指出的那样,如果直接从用户那里传入$username,那么你就有一个很大的安全漏洞。$email你肯定必须以某种方式处理它。

于 2013-01-31T14:24:43.860 回答
1

每个 Inner join 子句都需要有一个谓词或“ON”条件来指定连接两个表时要执行的一个或多个规则......

查询需要在 Inner Join 之后添加一个“ON”子句。我不确定那个条件应该是什么,但是,作为一个例子......

    $q = "SELECT username, email FROM login 
           INNER JOIN contact 
               On contact.username = login.userName 
           WHERE login.username = '$username' OR contact.email = '$email'";
于 2013-01-31T14:19:52.967 回答
1

您的加入有问题,因为您应该确定要加入的列!

例如 NNER JOIN contact On contact.id= login.contactId

于 2013-01-31T14:22:36.580 回答