JS XMLHttpRequest to PHP Page to Execute MSSQL Query - javascript

I'm having an issue with an XMLHttpRequest. Basically, an HTML button makes a call to the deleteItem function, which then makes a call to the other function. Each of these two functions makes the XHR to a php page in order to remove tuples from two different database tables.
Here's the code (variables renamed to generics):
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);
}
}
And here's the PHP page that it makes its two calls to:
//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);
}
Here's what I know for sure:
The queries are phrased correctly and have no syntax errors.
The queries are calling the correct tables.
The first function works as it should by deleting the correct tuples from the first table.
The second function fails to delete anything from the second table
My question is: Why would the first function work correctly, but not the second?
Edits:
$_REQUEST['q'] is equal to the SQL Query, in this case "DELETE FROM MyOtherTable WHERE FOREIGN_KEY = 'asdf';"
$_REQUEST['p'] is the SQL command I'm using, in this case "DELETE".
sqlsrv_errors() returns nothing, because it's never being called. Near as I can tell, the query executes successfully, it's just that nothing happens. How I know this:
I know the XHR passes successfully, because the IE developer tools Network tab says this:
sql.php?q=SELECT * FROM MyOtherTable WHERE FOREIGN_KEY = 'asdf';&p=SELECT
The above GET gives a status 200 code.
If it had failed, JS would pop an alert that said "Deletion failed" and then would give the error. Instead, it pops an alert that says "Deletion succeeded", which only happens if the query succeeds, and thus sqlsrv_errors() is not called.
At the suggestion of Zhorov, I've put in sqlsrv_rows_affected() to determine exactly what is happening. It seems that the same number of affected rows is reported each time, regardless of how many rows match the condition in the SQL statement, or even if there are any rows to affect. This behavior only occures in Internet Explorer. In Chrome, both functions behave as they should.
Major Edit:
It looks like the scope of this problem has changed. By temporarily disabling caching in IE, I've been able to run both files as intended, with no errors. I'm not sure why IE decided to cache it, but the question now has become what can be done to the program to disable or work around the caching in IE? I can hardly expect every user to do this themselves.

I will suggest something, that may help you. Your DELETE statement executes, but does not delete rows, because there are no rows that match WHERE condition.
It is not clear what are your table definitions and what is the actual data (I suppose that 'asdf' is just an example), but I had similar test case and this was a solution.
Check the number of rows modified by the last statement executed with sqlsrv_rows_affected().
Just put one additional line in your script:
...
$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];
}
...
So, if this statement is executed without errors and there are 0 rows affected, then one possible reason may be the fact, that FOREIGN_KEY column seems to be of type varchar/nvarchar/text.
If values in FOREIGN_KEY column contains any special characters, you have to consider the encoding issues when you pass this DELETE statement.
This also will explain the fact, that first function work correctly, while the second one fails.
First function deletes records with WHERE condition based on numeric column values, while the second function deletes records with WHERE condition based on text column values.
How to test the statement:
With SQL Server Management Studio and see the result and affected rows.
With your code, just put INSERT statement before the DELETE statement and check again 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];
}
...
Information about sqlsrv_rows_affected() can be found here.
Update:
User information from php.net:
If the sql contains INSERT, UPDATE or DELETE statements, the number of affected rows must be consumed.
The sqlsrv_query returns a sql cursor that must be read to finish the transaction, if the result is non false.
This same is valid for sqlsrv_execute. In this case the cursor must be also read using the prepared statement handle.
...
$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];
}
...
Another solution is to place SET NOCOUNT ON at the top of the sqlsrv statement and all called procedures, functions and triggers.
...
$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];
}
...

Related

Why am I getting alert of "Wrong login details." 4 times as I have 4 user in database

if(isset($_POST['signin'])){
$password = $_POST['password'];
$email = $_POST['email'];
$query = "SELECT * from `accounts`;";
if(count(fetchAll($query)) > 0){ //this is to catch unknown error.
foreach(fetchAll($query) as $row){
if($row['email']==$email&&$row['password']==$password){
$_SESSION['login'] = true;
$_SESSION['type'] = $row['type'];
header('location:admin.php');
}else{
echo "<script>alert('Wrong login details.')</script>";
header("Location:login.php");
}
}
}else{
echo "<script>alert('Error.')</script>";
}
}
When I enter wrong email address I get an alert 4 times, and I also have 4 users. Does that mean each row is getting counted and I am getting alert after each user is checked. Please help me fix this.
You're getting 4 messages because each of the 4 values in the database doesn't match the value you are checking. You need to move the "Wrong login details" alert out of your foreach loop and instead use $_SESSION['login'] to indicate whether there was a match or not, if not, then output the "Wrong login" alert. Something like this:
$_SESSION['login'] = false;
$users = fetchAll($query);
if (count($users) > 0) { //this is to catch unknown error.
foreach ($users as $row){
if($row['email']==$email&&$row['password']==$password){
$_SESSION['login'] = true;
$_SESSION['type'] = $row['type'];
break;
}
}
if ($_SESSION['login']) {
header('location:admin.php');
}
else {
echo "<script>alert('Wrong login details.')</script>";
}
}
Notes
You should never store passwords in plain text, instead use password_hash and password_verify to store and check them.
You are fetching all the results of the query twice, you should just fetch once into an array and then iterate the array in the foreach loop. My code does that.
You can't echo an alert and use a header statement. Presuming this is login.php, there is no need for the header statement if you fail anyway.
It would be better to simply SELECT * FROM accounts WHERE email = '$email' and see if any rows were returned, rather than iterating through all values in the table. This will save time when the table gets large. If you do that, you will need to use a prepared statement to avoid the risk of SQL injection. See this Q&A for details on how to do that.

Mysqli query not working in PHP code after been sent by Ajax

I'm having a bit of trouble with some Myqsli query.
$sqlselect = "SELECT visitatori_id FROM visitatori WHERE visitatori_nome='".$nome."' AND visitatori_cognome='".$cognome."' AND
visitatori_orastart='".$time."' AND visitatori_idsede='".$idsede."'";
if ($conn->query($sqlselect) === TRUE)
{
$resultz = $conn->query($sqlselect);
$rowz = $resultz->fetch_assoc();
$id = $rowz["visitatori_id"];
$data = date('dmY');
$arr = $id."/".$data.$idref.$idrep.$idsede;
$JSON->value = $arr;
$json = json_encode($JSON);
echo $json;
break;
}
else
{
$JSON->value = $conn->error;
$json = json_encode($JSON);
echo $json;
break;
}
The query launched on the DB works with no problems at all.
But if i try to launch it in the PHP code, the if returns false, and the $conn->error is just "".
I've searched a lot but I couldn't find anything that could at least show to me the errors.
EDIT
I know this code can be injected, but before the mysqli statements I've always done some tests with normal query, anyway thanks for the reminder.
You're condition check needs to either check for "not false" or for a loose true (==)(mysqli_query returns mysqli_result object on successful select and false on failure: http://php.net/manual/en/mysqli.query.php).. and you are executing the same query twice when I'm sure you do not mean to. Also, as others have said, this code is prone to injection (see: http://php.net/manual/en/mysqli.real-escape-string.php, https://en.wikipedia.org/wiki/SQL_injection).
if( ($res = $link->query($queryString)) ){
if( $res->num_rows > 0 ){
$row = $res->fetch_assoc();
/* Do something with result */
}else{
/* No results, do something else */
}
}
and before this point... you should escape all necessary data to avoid injection attack:
$link->escape_string($aString);

Add and retrieve to mysql

I am building a small php application where you can add people and then see them on a page. When I was simply adding it went fine, but then I started using a switch and now it doesn't work to either add or retrieve. I cannot see any problem in my syntax, can anyone see something wrong?
php
<?php
$con = mysql_connect("hostWasHere","username","password");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("dbIsHere", $con);
try{
switch($_POST['action'])
{
case 'retrieve':
$show=mysql_query("Select * from test",$con);
while($row=mysql_fetch_array($show)){
echo "<li><b>$row[firstName]</b> : $row[lastName]</li>";
}
mysql_close($con);
break;
case 'new':
$sql="INSERT INTO test (firstName, lastName)
VALUES
('$_POST[fname]','$_POST[lname]')";
if (!mysql_query($sql,$con))
{
die('Error: ' . mysql_error());
}
echo "1 record added";
mysql_close($con);
break;
}
}
?>
The javascript using this is :
function saveToServer() {
alert("clicked");
$.post("api.php", {
'action': "new",
'fname': $('#fname').val(),
'lname': $('#lname').val()
},
function () {
alert("succes");
}
);
}
function getFromServer() {
console.log("in get!");
$.ajax({
type: "post",
url: "api.php",
data: "action=retrieve",
success: function (data) {
$("#comment").html(data);
console.log("success!");
}
});
}
You are using a try block without any catch or finally – this doesn't work. Most likely, your server is configured not to output any errors, so it dies silently.
A few other remarks:
As pointed out in the comments, please use PDO or MySQLi instead of the deprecated MySQL class.
Beware of SQL injection and always sanitize properly, no excuses. (My code below with PDO uses prepare and takes care of this.)
Use quotes when you're accessing an array with a string as key: $_POST['fName'] or $row["lName"], as opposed to $row[lName].
Output all errors while you're developing your page by adding error_reporting(E_ALL) at the top of your file. Note that server settings may still suppress the error output, but this generally takes care of everything.
Using a switch statement with a lot of code is never a good idea; you want to keep all code there rather lightweight or switch to a combination of if, else if and else.
Enough talk. Here's my edit for your page, using PDO instead of the deprecated MySQL family.
<?php
error_reporting(E_ALL);
// PDO has more options to read about
// for initialization, but this should do for now
$con = new PDO("host=host;dbname=db_here", "username", "password");
if (!$con) {
die('Could not connect: !');
}
// Do some validation on $_POST before using it.
$action = '';
if(isset($_POST['action'])) {
$action = $_POST['action'];
}
if($action == 'retrieve') {
$sql = $con->execute('SELECT * FROM test');
$rows = $sql->fetchAll(PDO::FETCH_ASSOC);
foreach($rows as $row) {
echo '<li><b>'.$row['firstName'].'</b> : '.$row['lastName'].'</li>';
}
$con = null;
}
else if($action == 'new') {
$sql = $con->prepare('INSERT INTO test (firstName, lastName)
VALUES (?, ?)');
// TODO: more checks on fname and lname before accepting
if(isset($_POST['fname']) || isset($_POST['lname'])) {
$result = $sql->execute( array($_POST['fname'], $_POST['lname']) );
if(!$result) {
die('Error occured');
}
else {
echo 'Added 1 row';
}
}
$con = null;
}
else {
// TODO: Default page
}
PS: Please don't ever trust user input. The code is still inserting $_POST values rather blindly (just checking that they're at least set), further checks with is_scalar() and some length checks would probably be good.
I hope this can help – good luck with your project!

Will this huge javascript array loaded from a database crash my website?

So on this website I'm making (who knows if i'll actually finish it lol) when someone opens up the new user page, php echos into a javascript script all the usernames from the database to create an array.
<script type="text/javascript">
var allUsers = ['!' <?php
$result = mysql_query("SELECT username FROM users ") or die("error " .mysql_error());
$usersArray = array();
while($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$usersArray[] = $row['username'] or die("error ". mysql_error());
}
foreach ($usersArray as $name) {
echo ',' . json_encode($name );
}
?> , ];
the point of this is to have a live checker so if you type in a username that already exists, red text shows up next to the username input. But let's say I get 1,000,000 users (completely theoretical). Fortunately, the array only gets created at the beginning of the web page load. But will the function that checks if the username already exists in the huge array and gets called everytime someone changes the text in the username input put too much stress on the script and crash the website? If so, is there a better way to do what I'm describing?
Here's the rest of the code
function contains(a, obj) {
var i = a.length;
while (i--) {
if (a[i] === obj) {
return true;
}
}
return false;
}
function onUserChange() { //gets called onkeypress, onpaste, and oninput
if(contains(allUsers, str)) {
div.innerHTML = "Username already exists";
div.style.color = "red";
userValid = false;
}
}
</script>
Something along these lines. ( with jQuery and PDO ) - note - code is not tested.
var keyTimer, request;
$('namefield').blur(function(){
onUserChange();
});
$('namefield').keyup(function(){
onUserChange();
});
function onUserChange() { //gets called onkeypress, onblur
keyTimer = setTimeout(function(){
if(request && request.readystate != 4){
//cancel a previous request if a new request is made.
request.abort();
}
request = $.post(
'http://yoursite.com/location/of/username/script.php', //post data to server
{username : $('namefield').val()},
function(data){
if(data == 0 ) { //might be a string here
alert( 'the name is ok to use.' );
}else{
alert( 'someone has this name already.' );
}
}
);
}, 500); //overwrite previous timeout if user hits key within 500 milliseconds
}
Then in the backend
$sql = 'SELECT id FROM users WHERE username = :username';
//insert from post username but we are good programers and are using PDO to prevent sql injection.
//search for the username in the db, count the number of users or rows should be 1 someone has it 0 no one has it assuming its unique.
$stmt = $Pdo->prepare($sql);
$stmt->execute(array(':username', $_POST['username']));
echo $stmt->rowCount();
exit();
etc.....
Do not do it. My counsel is to use ajax to load the php file that will make a query asking only for the user that was typed in the input and retunr only a boolean value(exists=true / notexists=false)
Code example:
HTML(yourFile.html):
<script>
jQuery(document).ready(function(){
//When the value inside the input changes fire this ajax querying the php file:
jQuery("#inputUser").change(function(){
var input = jQuery(this);
jQuery.ajax({
type:"post",
url:"path/to/file.php",
data:input.val(),
success: function(data){
//if php returns true, adds a red error message
if(data == "1"){
input.after('<small style="color:#ff0000;">This username already exists</small>');
//if php returns false, adds a green success message
} else if(data == "0"){
input.after('<small style="color:#00ff00;">You can use this username</small>');
}
}
});
});
});
</script>
<input id="inputUser" type="text" name="username" value="">
PHP(path/to/file.php):
<?php
$username = $_REQUEST['username']; // The value from the input
$res = mysqli_query("SELECT id FROM users WHERE username='".$username."'"); // asking only for the username inserted
$resArr = mysqli_fetch_array($res);
//verify if the result array from mysql query is empty.(if yes, returns false, else, returns true)
if(empty($resArr)){
echo false;
} else{
echo true;
}
?>
As I can see you need to load the PHP code when your website is loading.
First, I recommend you to separate the code. The fact that you can mix Javascript with PHP doesn't mean it is the best practice.
Second, yes, it's not efficient your code since you make Javascript load the result so you can search into it next. What I suggest you is making the search in the server side, not in client side, because as you say, if you have 100 elements maybe the best is to load all the content and execute the function, but if you have 1,000,000 elements maybe the best is to leave the server to compute so it can make the query with SQL.
Third, you can do all this using Ajax, using Javascript or using a framework like jQuery so you don't have to worry about the implementation of Ajax, but you only worry about your main tasks.

Debugging MySQL query in PHP when called from other page

Page1 has an input form. I validate the input field with a JavaScript:
<input type="text" name="frmBrand" size="50" onkeyup="BrandCheck();" maxlength="100" id="frmBrand" />
<span id="frmBrand_Status">Enter existing or new brand</span>
In the JavaScript I then call a PHP script:
function BrandCheck()
{
var jsBrandName = document.forms["AddPolish"]["frmBrand"].value;
if (jsBrandName !==null || jsBrandName !== "")
{
document.getElementById("frmBrand_Status").textContent = jsBrandName
// alert(jsBrandName);
var xmlhttp = new XMLHttpRequest();
var url = "CheckBrand.php";
var vars = "jsBrandName="+jsBrandName;
xmlhttp.open("POST",url,true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.onreadystatechange = function()
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
var return_data = xmlhttp.responseText;
document.getElementById("frmBrand_Status").innerHTML = return_data;
}
}
xmlhttp.send(vars);
document.getElementById("frmBrand_Status").innerHTML = "processing.....";
}
}
So far so good. I do get results from the CheckBrand.php because it changes the frmBrand_Status. But I can't get any database results from the PHP page.
<?php
if(mysqli_connect_errno()) { //if connection database fails
echo("Connection not established ");
}
//by now we have connection to the database
else
{
if(isset($_POST['jsBrandName']))
{ //if we get the name succesfully
$jsBrandName = $_POST['jsBrandName'];
$dbBrandName = mysql_real_escape_string($jsBrandName);
if (!empty($dbBrandName))
{
$dbBrandName = $dbBrandName . "%";
$sqlQuery = "SELECT `BrandName` FROM `Brand` WHERE `BrandName` like '$dbBrandName' ORDER BY `BrandName`";
$result = mysqli_query($con, $sqlQuery);
$NumRows = mysqli_num_rows($result);
// $BrandName_result = mysql_fetch_row($BrandName_query);
echo "Result " . $dbBrandName . " ----- ". $jsBrandName . "Number rows " .$NumRows. " BrandName = " .$result. " SQL " .$sqlQuery;
if( $BrandName_result = mysql_fetch_row($BrandName_query))
{
While ($BrandName_result = mysql_fetch_row($BrandName_query))
{
echo "Brand = " .$BrandName_result[0];
}
}
}
else
{
echo "dbBrandName = empty" . $dbBrandName;
}
}
}
?>
When doing this, the html page shows the constant change of the normal variables. For example when the input field holds "Clu" I get the following output the span ID frmBrand_Status:
Result Clu% ----- CluNumber rows BrandName = SQL SELECT `BrandName` FROM `Brand` WHERE `BrandName` like 'Clu%' ORDER BY `BrandName`
Which looks good as the brandname gets the % appended, but the Number of rows is not shown (empty field?), the SQL Query is shown and looks good, but I don't get any results.
And the if( $BrandName_result = mysql_fetch_row($BrandName_query)) section will not be reached, so there definitely is something going wrong in calling the query.
When I run that same query through PHPMyAdmin, i do get the result I expect, which is 1 row with a brandname.
I'm using firebug to try and troubleshoot the SQL Query, but I can't find where I can check this and I probably can't since PHP is serverside. correct? But how should I then trouble shoot this?
Found what was wrong.
The $con string I was using to open the database was no longer available. On other pages in the site, the $con is available, I load the database using an include script on my index page. But it seems that the variable gets lost when it is called through the XMLHttpRequest(). Which is logical now I think of it, since this can also be a call to a remote server. So my CheckBrand.php page was just missing the $con var to connect to the database.

Categories