I'm trying to create a validation for a form. When a user fills out the form, it is supposed to run a set of queries. The first is to check if a records already exists in the table. If it does exist, then it doesn't need to run the the next 2 queries, which are to INSERT and UPDATE.
I'm not sure what I am doing wrong, but the table already has an existing record. After checking the table, it still runs the INSERT and UPDATE queries. They should not fire. It should not do anything.
Here is my code: * I'm starting my code from the for loop, which is just taking an array of BOL numbers and CONTAINER numbers that the user manually selected. I exploded the array, but I will not show that code as I do not think it is necessary to show in this case *
<?php
for($i = 0; $i < $count; $i++)
{
$bolService = $bolArray[$i];
$conService = $conArray[$i];
$checkService = "SELECT * FROM import_service WHERE bol = '" . $bolService . "' AND container = '" . $conService . "'";
$checkSerRes = mysql_query($checkService);
$checkSerNum = mysql_num_rows($checkSerRes);
if($checkSerNum > 0)
{
$successService = false;
}
elseif($checkSerNum = 0)
{
$sql_query_string = mysql_query
("INSERT INTO import_service (bol, container) VALUES ('$bolService','$conService')");
$updateService = mysql_query ("UPDATE import_dispatch_details SET SERVICE = 'Y'
WHERE BOL_NUMBER = '$bolService' AND CONTAINER = '$conService')");
$successService = true;
}
}
// javascript fires an ALERT message in this next set of code
if($successService = true)
{
echo ("<script language='javascript'>
window.alert('Record has been saved')
window.location.href=''
</script>");
}
// if checkSerNum > 0, then it should skip the INSERT and UPDATE and fire the code below
elseif($successService = false)
{
echo ("<script language='javascript'>
window.alert('There was an error saving the record')
window.location.href=''
</script>");
}
?>
I'm not sure why this is not working correctly. I need this validation to work. I'm sure there is an alternative method, but this is what I got.
Please help me make this work.
Thank you in advance.
This elseif($checkSerNum = 0) needs to be elseif($checkSerNum == 0)
You're presently doing an assignment instead of a comparison.
Including if($successService = true) and elseif($successService = false) so add another = sign.
Add error reporting to the top of your file(s) which will help during production testing.
error_reporting(E_ALL);
ini_set('display_errors', 1);
http://www.php.net/manual/en/function.mysql-error.php
Footnotes:
mysql_* functions deprecation notice:
http://www.php.net/manual/en/intro.mysql.php
This extension is deprecated as of PHP 5.5.0, and is not recommended for writing new code as it will be removed in the future. Instead, either the mysqli or PDO_MySQL extension should be used. See also the MySQL API Overview for further help while choosing a MySQL API.
These functions allow you to access MySQL database servers. More information about MySQL can be found at » http://www.mysql.com/.
Documentation for MySQL can be found at » http://dev.mysql.com/doc/.
This isn't quite efficient (you are selecting * from your table, which you aren't using - waste of memory?). Why don't you do something like this:
for ($i = 0; $i < $count; $i++)
{
$bolService = $bolArray[$i];
$conService = $conArray[$i];
$recordExists = false;
$result = mysql_query("SELECT COUNT(*) AS recordCount FROM import_service WHERE bol = '" . $bolService . "' AND container = '" . $conService . "'");
if ($result) {
$row = mysql_fetch_assoc($result);
$recordExists = ($row['recordCount'] >= 1);
}
if ($recordExists)
{
$successService = false;
}
else
{
$sql_query_string = mysql_query
("INSERT INTO import_service (bol, container) VALUES ('$bolService','$conService')");
$updateService = mysql_query
("UPDATE import_dispatch_details SET SERVICE = 'Y'
WHERE BOL_NUMBER = '$bolService' AND CONTAINER = '$conService')");
$successService = true;
}
}
P.S. mysql_* is officially deprecated. Please use PDO or MySQLi. Also, your code is potentially open to SQL Injection.
Related
Am new to php and working on a project. At the beginning there was 2 filters for which I didn't worry much in writing the sql query with 4 conditions. But now I've 8 different dropdowns and I need to write an optimized sql for filter functionality. As per conditions to be written counted, I need to write 256 conditions which is the worst idea at all.
Here the problem is, there is no mandatory filed to choose for filtering. This giving me the more problem in applying different approaches.
Is there any other alternative to achieve this issue? what would be the best idea for optimized query.
Example Code
if($_REQUEST['action']=='action_report'){
$v1 = $_POST['v1'];
$v2 = $_POST['v2'];
if(!empty($v1) && !empty ($v2)){
$sql = "SELECT * FROM TABLE WHERE v1=$v1 AND v2=$v2 AND action='action_report'";
}elseif(!empty($v1) && empty($v2)){
$sql = "SELECT * FROM TABLE WHERE v1=$v1 AND action='action_report'";
}elseif(empty($v1) && !empty($v2)){
$sql = "SELECT * FROM TABLE WHERE v2=$v2 AND action='action_report'";
}elseif(empty($v1) && empty($v2)){
$sql = "SELECT * FROM TABLE WHEREAND action='action_report'";
}
}
The code would look like this:
$sql = 'SELECT * FROM TABLE WHERE ';
$first = true;
foreach($_POST as $paramName => $value) {
if ($first) {
$sql .= "{$paramName}='{$value}'";
$first = false;
continue;
}
$sql .= " AND {$paramName}='{$value}'";
}
Since the $_POST is an array of the incoming variables you can go through on it with a simple foreach cycle and attach it to the SQL query string. The first possible parameter wont need an AND operator, so you have to handle it differently, that's why the $first variable is for.
However this code is has SQL injection vulnerabilities, so it's better to attach the parameter name and the value to the SQL string like this:
$sql .= ' AND ' . mysqli_real_escape_string($connection, htmlspecialchars($paramName)) . "='" . mysqli_real_escape_string($connection, htmlspecialchars($value)) . "'";
You will also receive empty values, you wouldn't like to attach to the SQL query string. So the final code needs to handle that too, and after a bit of formatting it would look like this:
$sql = 'SELECT * FROM TABLE WHERE ';
$first = true;
foreach($_POST as $paramName => $value) {
$protectedParamName = mysqli_real_escape_string($connection, htmlspecialchars($paramName));
$protectedValue = mysqli_real_escape_string($connection, htmlspecialchars($value));
if (empty($value)) {
continue;
}
if ($first) {
$sql .= "{$protectedParamName}='{$protectedValue}'";
$first = false;
continue;
}
$sql .= " AND {$protectedParamName}='{$protectedValue}'";
}
In the example the $connection variable is a mysqli object:
$connection = new mysqli(
$dbConfig['host'],
$dbConfig['user'],
$dbConfig['password'],
$dbConfig['databaseName'],
$dbConfig['port']
);
The foreach($_POST as $paramName => $value) goes through on each $_POST array values, so if you would you don't want some fields to be used in the SQL query, then you can use blacklist filtering, where you specify if the $paramName is in the blacklist, then you wont attach it to the SQL query.
For example:
$blackList = [
'action'
];
foreach($_POST as $paramName => $value) {
if (in_array($paramName, $blackList)) {
continue;
}
}
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];
}
...
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);
I'm having an issue appending data from loop. I am trying to append the result that is clicked on, but when theres multiple results every result is appended on click. I am using ajax to retrieve search results. Below is my php section. I think the issue is that every result has the same class so it appends every one, but I can't figure out how to identify only one
if(isset($_POST['inviteSearch'])) {
include_once "connect.php";
$con = getConnection();
$search = "%{$_POST['inviteSearch']}%";
$query = "SELECT FirstName,LastName FROM `Profiles` WHERE FirstName LIKE ? OR LastName LIKE ? ";
$stmt = $con->prepare($query);
$stmt->bind_param("ss", $search ,$search);
if(!($stmt->execute())) {
die(mysql_error());
} else {
$result = $stmt->get_result();
$output = '<ol>';
if(mysqli_num_rows($result) > 0) {
while($row = mysqli_fetch_assoc($result)){
$name = $row['FirstName'] . " " . $row['LastName'];
$output .= "
<li id='invitetoken'>
<p>$name</p>
</li>
<script>
$(document).ready(function(){
$('#invitetoken').click(function(){
$('.invitedSection').show();
$('.invitedList').append('<li><p>$name</p><button>×</button></li>');
});
});
</script>
";
}
} else {
$output .= "<h3>We could not find $search</h3>";
}
$output .= '</ol>';
echo "$output";
}
}
To start with the obvious, please use parameterized queries you are currently vulnerable to SQL injection attacks.
You are appending the same js repeatedly in your while loop, that is generally bad practice. I'm going to break this up a bit, since you have both php and JS issues
PHP
Here just generally cleaning up and using parameterized queries and class based mysqli (in line with the above suggestion comments). I also moved the javascript out of the loop as repeating it over and over doesn't achieve anything. Obviously haven't tested my changes but they are fairly boilerplate (see the docs)
if (!isset($_POST[''inviteSearch']) {
return;
}
$connection = new mysqli('host', 'user', 'password', 'schema');
$param = filter_input(INPUT_POST, 'inviteSearch', FILTER_SANITIZE_STRING);
// setup query
$query = "SELECT CONCAT(FirstName, ' ', LastName) AS name
FROM Profiles
WHERE (FirstName LIKE ? OR LastName LIKE ?)";
// prepare statement
$stmt = $connection->prepare($query);
// need variable bind for each tokenized parameter
$stmt->bind_param('ss', $param, $param);
$stmt->execute();
$results = $stmt->get_result();
$output = makeOutput($results);
// Siloing your presentational elements for clarity.
function makeOutput($results) {
if ($results->num_rows === 0) {
return "<h3>We could not find $search</h3>";
}
$output = '<ol>';
while ($row = $results->fetch_assoc()) {
$output .= "<li class='invitetoken'><p>{$row['name']}</p></li>";
}
$output .= '</ol>';
return $output;
}
JavaScript
A few things here, enclosed the function into an IIFE to keep it namespace contained, generally a good practice. The changes to the click handler let the callback handle the update dynamically for any matching class that is clicked. I reference this (in this case it is helpful to think of this as event.target) and use it to find the name to be appended. from there it is pretty similar to what you already had. Of note, I'm using let for variable definitions and template literal syntax for the string data, but you should look up their availability and decide whether you need to worry about old browser support :).
(function($) {
$(document).ready(function(){
$('.invitetoken').on('click', function() {
let name = $(this).children('p').text()
, string = `<li><p>${name}</p><button>×</button></li>`;
$('.invitedSection').show();
$('.invitedList').append(string);
});
});
})(jQuery);
we have a form that we can click on a number at the top of the form in order to load the according data, to be more specific i can have 4 inputs in my table in the database and when I click on number 2 which is the id of the data then it loads the data. We did that but now we want to update the clicked data and until now we cant find a way to GET the correct number(id) and place it in the UPDATE statement.
Below is the code of the clicked functions and of the UPDATE statement.
//Education Scripts
$("#updateEdu").click(function () {
$("#idE").css("display", "none");
var r = parseInt($("#idE").val(), 10) + 1;
$("#idE").val(r);
});
$('[data-row-ide]').click(function (e) {
e.preventDefault();
var fileName = 'addCV.php?idEdu='; //"addCV.php" the name of this file in your project, the "?" starts the GET parameters, idWork= sets the key for the GET parameter
var id = $(this).data('row-ide'); // this gets the id that we stored in the link's data attribute
var url = fileName + id; // then we add that id as the value for the "idWork" key
window.location = url; // esentially refresh this page with the id set as a GET parameter and make use of the logic we already have to load the info
});
<?php
$username = $_SESSION["username"];
if(isset($_POST['updateEdu'])){
$parts = parse_url($url);
parse_str($parts['query'], $query);
$id = $query['idEdu'];
$username = $_SESSION['username'];
$school = mysql_real_escape_string($_POST["school"]);
$degree = mysql_real_escape_string($_POST["degree"]);
$website = mysql_real_escape_string($_POST["website"]);
$start_date = mysql_real_escape_string($_POST["start_date"]);
$end_date = mysql_real_escape_string($_POST["end_date"]);
$start_year = mysql_real_escape_string($_POST["start_year"]);
$end_year = mysql_real_escape_string($_POST["end_year"]);
$degree_description = mysql_real_escape_string($_POST["degree_description"]);
if($start_year > $end_year){
echo 'The Start Year must be smaller than the End Year!';
$id=$id-1;
$good = false;
}
else{
$good = true;
}
if($good == true){
$query="UPDATE education
SET school = '$school', degree = '$degree', website = '$website', start_date='$start_date', end_date='$end_date', start_year='$start_year', end_year='$end_year', degree_description='$degree_description'
WHERE id='$id' AND username='$username'";
mysql_query($query)or die(mysql_error());
if(mysql_affected_rows()>0){
echo "<p>Record Updated<p>";
echo "<script type='text/javascript'>;
/window.location='addCV.php';
</script>";
}
else{
echo "<p>Error Updating Record<p>";
echo "<script type='text/javascript'>;
</script>";
}
}
}
else if(isset($_GET['idEdu'])){
// user clicked on one of oue id links to get here
// set the id the the value of the GET parameter for key "idWork"
$id = $_GET['idEdu'];
}
else{
// Formulate Query
// This is the best way to perform an SQL query
// For more examples, see mysql_real_escape_string()
$query = sprintf("SELECT school,degree,website,start_date,end_date,start_year,end_year,degree_description,id FROM education
WHERE username='%s' ORDER BY id LIMIT 1",
mysql_real_escape_string($username));
// Perform Query
$result = mysql_query($query);
// Check result
// This shows the actual query sent to MySQL, and the error. Useful for debugging.
if (!$result) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
// Use result
// Attempting to print $result won't allow access to information in the resource
// One of the mysql result functions must be used
// See also mysql_result(), mysql_fetch_array(), mysql_fetch_row(), etc.
while ($row = mysql_fetch_assoc($result)) {
$id = $row['id'];
}
}
To get the value of an elements attribute in jquery you use the attr() function like so:
$(element).attr('attributeName')
So you should change:
var id = $(this).data('row-ide');
into
var id = $(this).attr('row-ide');
in your function $('[data-row-ide]').click(function (e) {};