【问题标题】:JS XMLHttpRequest to PHP Page to Execute MSSQL QueryJS XMLHttpRequest 到 PHP 页面执行 MSSQL 查询
【发布时间】:2018-08-08 12:56:58
【问题描述】:

我遇到了 XMLHttpRequest 的问题。基本上,一个 HTML 按钮调用 deleteItem 函数,然后调用另一个函数。这两个函数中的每一个都将 XHR 转换为 php 页面,以便从两个不同的数据库表中删除元组。

这是代码(变量重命名为泛型):

JS:

//remove first item from first table
function deleteItem() {
    var conn = new XMLHttpRequest();
    var query = "DELETE FROM MyTable WHERE ID = " + arrayOfObjects[i][0] + ";";
    conn.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            deleteWorkflowProcess(arrayOfObjects[i][1], conn.responseText);
        }
    }

    conn.open("GET","../../db_query/sql.php?q=" + query + "&p=DELETE", true);
    conn.send();

}

//remove other items from other table
function deleteWorkflowProcess(s, r) {
    var conn = new XMLHttpRequest();
    var query = "DELETE FROM MyOtherTable WHERE FOREIGN_KEY = '" + s + "';";

    if (r == "Deletion succeeded.") {
        conn.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var response = conn.responseText;
                alert(response);
                window.location.replace("thissamepage.php");
            }
        }

        conn.open("GET","../../db_query/sql.php?q=" + query + "&p=DELETE", true);
        conn.send();
    } else {
        alert(r);
    }
}

这是它两次调用的 PHP 页面:

//set up connection
$serverName = "SERVER\MSSQLINSTANCE";
$connectionInfo = array("Database"=>"DATABASE");

if (isset($_REQUEST['q'])) {

    //establish connection
    $conn = sqlsrv_connect($serverName, $connectionInfo);

    if ($conn) {

        //delete data
        if ($_REQUEST['p'] == "DELETE") {
            $result = sqlsrv_query($conn, $_REQUEST['q']);
            if ($result) {
                echo "Deletion succeeded.";
            } else {
                echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
            }
        }

        //do some other stuff based on 'p' value
        //e.g. insert, update, etc.
    }

    sqlsrv_close($conn);
}

这是我确定的:

  • 查询措辞正确,没有语法错误。
  • 查询正在调用正确的表。
  • 第一个函数通过从第一个表中删除正确的元组来正常工作。
  • 第二个函数无法从第二个表中删除任何内容

我的问题是:为什么第一个函数可以正常工作,而第二个函数不行?

编辑: $_REQUEST['q'] 等于 SQL Query,在本例中为“DELETE FROM MyOtherTable WHERE FOREIGN_KEY = 'asdf';”

$_REQUEST['p'] 是我正在使用的 SQL 命令,在本例中为“DELETE”。

sqlsrv_errors() 不返回任何内容,因为它从未被调用过。据我所知,查询成功执行,只是什么也没发生。我怎么知道的:

  • 我知道 XHR 成功通过了,因为 IE 开发人员工具的网络选项卡是这样说的: sql.php?q=SELECT * FROM MyOtherTable WHERE FOREIGN_KEY = 'asdf';&p=SELECT
  • 上面的 GET 给出了一个状态码 200。
  • 如果失败,JS 会弹出“删除失败”的警报,然后给出错误。相反,它会弹出一个提示“删除成功”的警报,只有在查询成功时才会发生这种情况,因此不会调用 sqlsrv_errors()。

在 Zhorov 的建议下,我输入了 sqlsrv_rows_affected() 来确定到底发生了什么。似乎每次都报告相同数量的受影响行,无论有多少行与 SQL 语句中的条件匹配,或者即使有任何行要影响。此行为仅发生在 Internet Explorer 中。在 Chrome 中,这两个函数的行为都应有尽有。

主要修改: 看起来这个问题的范围已经改变了。通过暂时禁用 IE 中的缓存,我已经能够按预期运行这两个文件,没有错误。我不知道为什么 IE 决定缓存它,但现在的问题已经变成可以对程序做些什么来禁用或解决 IE 中的缓存?我几乎不能指望每个用户都这样做这个自己。

【问题讨论】:

  • sqlsrv_errors() 返回什么?然后你可以发布 $_REQUEST['q'] 值吗?谢谢!
  • 请告诉我这只是一个伪代码/示例,您不会尝试在生产服务器上推送 - 具有从 http GET 获取 sql 并直接在 DB 中执行的 php 脚本?不逃?这就像大喊“请窃取我所有的数据并删除我所有的表”。将 sql 移动到 php 脚本并仅传递需要删除的项目的 ID(请转义)
  • @Michal Bieda 感谢您的关注。我知道 SQL 注入的问题。这将是生产,但还远未达到这一点。目前,我正在工作。数据库中甚至还没有任何真实数据,所以不用担心有人窃取任何东西。别担心:SQL 注入将在最后介绍。

标签: javascript php sql-server internet-explorer


【解决方案1】:

我会建议一些东西,这可能会对你有所帮助。您的 DELETE 语句会执行,但不会删除行,因为没有符合 WHERE 条件的行。 目前尚不清楚您的表定义是什么,实际数据是什么(我想“asdf”只是一个示例),但我有类似的测试用例,这是一个解决方案。

检查由sqlsrv_rows_affected() 执行的最后一条语句修改的行数。 只需在脚本中添加一行:

...
$result = sqlsrv_query($conn, $_REQUEST['q']);
if ($result) {
    echo 'Rows affected: '.sqlsrv_rows_affected($result).'</br>';
    echo "Deletion succeeded.";
} else {
    echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
}
...

因此,如果此语句执行时没有错误并且有 0 行受到影响,那么一个可能的原因可能是 FOREIGN_KEY 列的类型似乎是 varchar/nvarchar/text。 如果 FOREIGN_KEY 列中的值包含任何特殊字符,则在传递此 DELETE 语句时必须考虑编码问题。

这也将解释这样一个事实,即第一个功能正常工作,而第二个功能失败。 第一个函数根据数值列值删除具有 WHERE 条件的记录,而第二个函数根据文本列值删除具有 WHERE 条件的记录。

如何测试语句:

使用 SQL Server Management Studio 并查看结果和受影响的行。

使用您的代码,只需将 INSERT 语句放在 DELETE 语句之前并再次检查 sqlsrv_rows_affected()

...
$sql = "INSERT MyOtherTable (FOREIGN_KEY) VALUES ('asdf');"; 
$sql = $sql + $_REQUEST['q'];
$result = sqlsrv_query($conn, $sql);
if ($result) {
    echo 'Rows affected: '.sqlsrv_rows_affected($result).'</br>';
    echo "Deletion succeeded.";
} else {
    echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
}
...

关于sqlsrv_rows_affected()的信息可以在here找到。

更新:

来自php.net的用户信息:

如果 sql 包含 INSERT、UPDATE 或 DELETE 语句,则必须消耗受影响的行数。 sqlsrv_query 返回一个 sql 游标,如果结果不为假,则必须读取该游标才能完成事务。 这同样适用于 sqlsrv_execute。在这种情况下,游标也必须使用准备好的语句句柄来读取。

...
$result = sqlsrv_query($conn, $_REQUEST['q']);
if ($result) {
    while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
    }
    echo 'Rows affected: '.sqlsrv_rows_affected($result).'</br>';
    echo "Deletion succeeded.";
} else {
    echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
}
...

另一种解决方案是将 SET NOCOUNT ON 放在 sqlsrv 语句和所有调用的过程、函数和触发器的顶部。

...
$sql = "SET NOCOUNT ON;"; 
$sql = $sql + $_REQUEST['q'];
$result = sqlsrv_query($conn, $sql);
if ($result) {
    echo 'Rows affected: '.sqlsrv_rows_affected($result).'</br>';
    echo "Deletion succeeded.";
} else {
    echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
}
...

【讨论】:

  • 好建议,这肯定会澄清很多。在对 IE 和 Chrome 进行彻底测试后,我确定它仅适用于 Chrome。在 IE 中,它一直告诉我有 5 行受到影响,尽管事实上没有符合条件的行。在 Chrome 中,不会发生这种行为。
  • 另外值得一提的是,尽管它说有 5 行受到影响,但无论有多少行符合条件,都不会删除任何行。
  • @MaclainAnderson 更新了答案。
  • 我尝试在回显行之前读取语句光标,但它仍然什么也没做。如上所述,它说有 5 行受到影响(可能只有 2 行),但没有任何内容被删除。
  • @MaclainAnderson SET NOCOUNT ON 怎么样?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多