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!
Related
I've tried to pass the "hide" value for delete a record. But the JS function send the data but the mysql code don't work.
With the "insert to" it works, for this it's strange that the same code don't work.
This is my code.
<script type="text/javascript">
function invia()
{
var hides = document.getElementById('hide').value;
$.ajax({
type: 'POST',
url: "note_db_php/delete_db_note.php",
data: {"hide": hides},
success: function(data){
console.log("Dati inviati");
},
error: function(data) {
console.log("Dati non inviati");
}
});
};
</script>
and this is the delete page;
<?php
$servername = "";
$username = "";
$password = "";
$dbname = "";
$hide = $_POST["hide"];
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// sql to delete a record
$sql = "DELETE FROM note WHERE id='$hide'";
if ($conn->query($sql) === TRUE) {
echo "Record deleted successfully";
} else {
echo "Error deleting record: " . $conn->error;
}
$conn->close();
?>
The console.log it work, and print "Dati inviati". So really, I don't understand. I have not error's message. But still don't work.
I have no idea why your code is not working -- you haven't described in any detail what error messages you are getting. But what other problem you have is that you are leaving yourself open to SQL Injection attacks and so you should be using a prepared statement. If this also corrects your problem (doubtful), that's a bonus:
$stmt = $conn->prepare("DELETE FROM note WHERE id=?");
/* Bind our parameter: */
$stmt->bind_param('i', $hide); // assuming $hide is an integer value, else use 's' for string
$success = $stmt->execute(); // execute the statement
if (!$success) {
error code here
}
$stmt->close();
I think the issue is with the sql query - $sql = "DELETE FROM note WHERE id=$hide";
Can you put the $hide in single quotes and try?
$sql = "DELETE FROM note WHERE id='$hide'"; // this will work
here your problem in sql syntax, and one line
enter code here
after else open on your code that causing error
updated query here , its working
// sql to delete a record
$sql = "DELETE FROM note WHERE id='$hide'";
if ($conn->query($sql) === TRUE) {
echo "Record deleted successfully";
} else {
echo "Error deleting record: " . $conn->error;
}
The attribute dataType is missing and type should be method.
$.ajax({
url:"note_db_php/delete_db_note.php",
method:'POST',
dataType:'json',
data:{
"hide": hides
},
success:function(data) {
console.log("Dati inviati");
},
error: function (request, status, error) {
console.log("Dati non inviati");
}
});
Replace your query -
$sql = "DELETE FROM note WHERE id='$hide'";
With below one -
$sql = "DELETE FROM note WHERE id = ".$hide;
And on the ajax end please console your data. If it is giving error then please echo your query (echo $sql), and copy and run the query in PHPMyAdmin.
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'll make this as short and sweet as possible.
I have this script called usernameget.php which echos the currently logged in username:
<?php
include 'functions.php';
include 'db_connect.php';
sec_session_start();
$userId = $_SESSION['user_id'];
if(login_check($mysqli) == true) {
$con=mysqli_connect("localhost","myusername","mypass","mysqldb");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$result = mysqli_query($con,"SELECT members.username FROM members WHERE id= $userId");
while ($row = mysqli_fetch_assoc($result))
{
echo $row['username'];
}
/* free result set */
mysqli_free_result($result);
mysqli_close($con);
} else {
echo 'Null User <br/>';
}
?>
This script uses functions.php (part of a secure login script located here: http://www.wikihow.com/Create-a-Secure-Login-Script-in-PHP-and-MySQL#Create_PHP_Functions ) in order to function. sec_session_start(); is just a custom session_start, but functions.php also makes it possible to get the username via $user_id.
The problem is, when I include usernameget.php in the main page (which also uses functions.php to secure,) it throws errors because it's trying to redeclare sec_session_start();
I can strip usernameget.php of this security but obviously since it banks on functions.php / sec_session_start(); it doesn't work afterwards. I've tried to write a specific USERNAMEGETfunctions.php without the session stuff for usernameget.php to use but I'm not adept enough to get it working, and it feels like an inelegant solution.
So as I understand it: functions.php and sec_session_start(); are used to secure the main page so the includes on the main page can't use functions.php or it will conflict. Would anyone be able to show me how to get this script going without redeclaring/conflicting?
Included below is the entire functions.php
<?php
function sec_session_start() {
$session_name = 'sec_session_id'; // Set a custom session name
$secure = false; // Set to true if using https.
$httponly = true; // This stops javascript being able to access the session id.
ini_set('session.use_only_cookies', 1); // Forces sessions to only use cookies.
$cookieParams = session_get_cookie_params(); // Gets current cookies params.
session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], $secure, $httponly);
session_name($session_name); // Sets the session name to the one set above.
session_start(); // Start the php session
session_regenerate_id(); // regenerated the session, delete the old one.
}
function login($email, $password, $mysqli) {
// Using prepared Statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password, salt FROM members WHERE email = ? LIMIT 1")) {
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
$stmt->bind_result($user_id, $username, $db_password, $salt); // get variables from result.
$stmt->fetch();
$password = hash('sha512', $password.$salt); // hash the password with the unique salt.
if($stmt->num_rows == 1) { // If the user exists
// We check if the account is locked from too many login attempts
if(checkbrute($user_id, $mysqli) == true) {
// Account is locked
// Send an email to user saying their account is locked
return false;
} else {
if($db_password == $password) { // Check if the password in the database matches the password the user submitted.
// Password is correct!
$user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
$user_id = preg_replace("/[^0-9]+/", "", $user_id); // XSS protection as we might print this value
$_SESSION['user_id'] = $user_id;
$username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username); // XSS protection as we might print this value
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512', $password.$user_browser);
// Login successful.
return true;
} else {
// Password is not correct
// We record this attempt in the database
$now = time();
$mysqli->query("INSERT INTO login_attempts (user_id, time) VALUES ('$user_id', '$now')");
return false;
}
}
} else {
// No user exists.
return false;
}
}
}
function checkbrute($user_id, $mysqli) {
// Get timestamp of current time
$now = time();
// All login attempts are counted from the past 2 hours.
$valid_attempts = $now - (2 * 60 * 60);
if ($stmt = $mysqli->prepare("SELECT time FROM login_attempts WHERE user_id = ? AND time > '$valid_attempts'")) {
$stmt->bind_param('i', $user_id);
// Execute the prepared query.
$stmt->execute();
$stmt->store_result();
// If there has been more than 5 failed logins
if($stmt->num_rows > 5) {
return true;
} else {
return false;
}
}
}
function login_check($mysqli) {
// Check if all session variables are set
if(isset($_SESSION['user_id'], $_SESSION['username'], $_SESSION['login_string'])) {
$user_id = $_SESSION['user_id'];
$login_string = $_SESSION['login_string'];
$username = $_SESSION['username'];
$user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
if ($stmt = $mysqli->prepare("SELECT password FROM members WHERE id = ? LIMIT 1")) {
$stmt->bind_param('i', $user_id); // Bind "$user_id" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
if($stmt->num_rows == 1) { // If the user exists
$stmt->bind_result($password); // get variables from result.
$stmt->fetch();
$login_check = hash('sha512', $password.$user_browser);
if($login_check == $login_string) {
// Logged In!!!!
return true;
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
}
?>
Don't use plain include for core function libraries, the kind which tend to get included in ALL your scripts. Use include_once instead, so that PHP will only ever include the file once, and then ignore any further include attempts. This will prevent your function redeclaration errors.
You must use require_once instead include_once because your program not will run without that files...
include_once produce warning when try to include the file and it fails.
require_once produce fatal error when try to include the and it fails.
For core libs, you should use require_once. (http://www.php.net/manual/pt_BR/function.require.php)
require is identical to include except upon failure it will also produce a fatal E_COMPILE_ERROR level error. In other words, it will halt the script whereas include only emits a warning (E_WARNING) which allows the script to continue.
PHP PAGE:
<?php
include "linkpassword.inc";
function showVotes()
{
$showresult = mysql_query("SELECT * from mms") or die("Invalid query: " . mysql_error());
$row = mysql_fetch_assoc($showresult);
}
function addVote()
{
$sql= "UPDATE mms SET votes = votes+1 WHERE color = '".$_POST['color']."'";
$result= mysql_query($sql) or die(mysql_error());
return $result;
}
addVote();
showVotes();
?>
I am trying to get the output of the array to load into a JavaScript page where I can break up the array into seperate divs that have IDs assigned to them. Here is what I tried
<script>
$(document).ready(function () {
$('.answer').click(function (e) {
var color = $(this).attr("data-color");
$.ajax({
type: 'POST',
url: 'mm.php',
data: { color: color},
dataType: 'json',
cache: false,
success: function(showVotes) {
$('#rvotes').html(showVotes[0]);
},
error: function (jqXHR) {
}
})
})
});
</script>
Where am I going wrong??
From what you've posted in comments, what you have is an array of objects.. not html, as your function seems to indicate. Depending on what you want done, the answer would be either of the following, to access that object's properties:
showVotes[0].votes
Or
showVotes[0]['votes']
Eg:
$('#rvotes').html(showVotes[0].votes);
Or etc.
Second attempt:
Firstly, change your current 'showVotes' function to this:
function showVotes()
{
$showresult = mysql_query("SELECT * from mms") or die("Invalid query: " . mysql_error());
while ($row = mysql_fetch_assoc($showresult)) {
$response[] = $row;
}
return json_encode($response);
}
Secondly, remove your 'connected successfully' text from the page, as well as any other text generated by anything else(aka, the other function which returns a result pointer). I may be wrong, but it would seem to me that the generation of this other text is causing the returned json to be interpreted as malformed.
Quick explanation on PDO:
try {
$dbh = new PDO("mysql:host=localhost;dbname=dbname", "user", "password");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $e) {
echo "Error! Could not connect to database: " . $e->getMessage() . "<br/>";
die();
}
Connecting to the database.. This is how I've learned to do it, though I've been warned(and downvoted) to not check for errors this way, though it was never explained why.
Database interaction:
$stmt = $dbh->prepare("UPDATE mms SET votes = votes+1 WHERE color = :color");
$stmt->bindParam(":color",$_POST['color']);
$stmt->execute();
Result use:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$response[] = $row;
}
And so on and so forth. PDO escapes the values for you, so you don't have to worry about injection attacks.