I have a little login script.
function login($sql) {
try {
$fbhost = "localhost";
$fbname = "foodbank";
$fbusername = "root";
$fbpassword = "";
$DBH = new PDO("mysql:host=$fbhost;dbname=$fbname",$fbusername,$fbpassword);
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$STH = $DBH->query($sql);
$STH->setFetchMode(PDO::FETCH_ASSOC);
session_start();
if ($row = $STH->fetch()) {
$_SESSION['username'] = "$row[username]";
header("Location:index.php");
}
} catch(PDOException $e) {
echo $e->getMessage();
}
}
EDITS:
index.php
$sql = "SELECT username from users where username = ". $_POST['username'] ." AND password = ". $_POST['password'] ."";
login($sql);
Changed above from insert to select query. Now I get new error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'pvtpyro' in 'where clause'
Based on your latest edit: You can't fetch results with PDO after executing an INSERT query. See here: http://www.php.net/manual/en/pdostatement.fetch.php#105682
Edit: I suppose, since the function's called "login", you want to have something like this as $sql: "SELECT password FROM users WHERE username = :username", and then iterate over the results with the while loop, and then log in the user if the password matches?
Edit2: Based on your edit to provide a SELECT query: DO NOT USE THIS QUERY. What you are doing is NOT SQL injection proof. Never ever use variables from user input (i.e. $_POST, $_GET et al) and put them unfiltered into an SQL query. Please look up the term "prepared statements" here at SO or Google.
As you can see, since you forgot to put single ticks (apostrophes) before and after the double quotes, MySQL thinks that your input refers to another column ("pvtpyro") instead of comparing the value in the column against a string. ALWAYS use the ":username", ":password" syntax (the one with prepended colons) or your queries will be unsafe and enormously dangerous to your application.
The constructor of PDO uses 2 variables which are not defined in the code you supplied - $fbhost and $fbname.
EDIT:
You're calling session_start() inside the while loop, which can cause errors. Take it out of the loop.
EDIT 2:
You should really debug the code. Either via putting die in different parts of the code, outputting some helpful information just before (which is the less preferred way) OR by using xdebug and an IDE, which will allow you to run line by line, and see the exact state of each variable and such.
If I undestand correctly, $data $STH->execute($data); should be an array, even if value is one. So, you may try replacing that query with $STH->execute(array($data));
edited:
Change your lines to this:
$data = array($_POST["username"], $_POST["password"]);
$sql = "INSERT INTO users (username, password) value (?, ?)";
$STH = $DBH->prepare($sql);
$STH->execute($data);
Seems to me that you're not connected to your database properly... I had this error earlier today and it was for that reason. Either that or you have an incorrect string
Related
I am trying to make simple form where you put user_id etc. etc. and it will change in mysql, which works pretty fine but the question is, is there any way I could instead of users_ids use usernames ? thanks
if(isset($_POST['btn-change'])) {
$account = strip_tags($_POST['account']);
$value = strip_tags($_POST['value']);
$string = strip_tags($_POST['string']);
$account = $DBcon->real_escape_string($account);
$value = $DBcon->real_escape_string($value);
$string = $DBcon->real_escape_string($string);
$sql = "UPDATE tbl_users SET $value='$string' WHERE user_id=$account";
if ($DBcon->query($sql) === TRUE) {
$msg1 = '<div class="alert alert-success">
<i class="fa fa-info" aria-hidden="true"></i> Successfully changed !
</div>';
} else {
$msg1 = '<div class="alert alert-danger">
<i class="fa fa-info" aria-hidden="true"></i></span> Something went wrong !
</div>';
}
$DBcon->close();
}
The original MySQL extension has been removed in PHP7 and was deprecated in PHP 5.5.
Don't be intimidated by PDO though, it's actually super simple and much better.
Require this code at the start of any PHP files that need to make database queries.
$host = "127.0.0.1";
$port = "3306";
$dbname = "NameOfTheDatabase";
$dsn = "mysql:host=$host;dbname=$dbname;port=$port;";
$dbuser = "UsernameForDatabase";
$dbpass = "PasswordForDatabase";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8");
$database = new PDO($dsn, $dbuser, $dbpass, $options);
Note that it can be improved upon drastically but for the sake of example, we'll keep things simple. Usually you would want to load this information from a protected config file.
Now let's say we want to select the user by their username.
$statement = $database->prepare("
SELECT user_id
FROM tbl_users
WHERE username LIKE :username
");
$statement->bindParam("username", $_POST['username'], PDO::PARAM_STR);
$statement->execute();
$result = $statement->fetch(PDO::FETCH_OBJ);
echo $result->user_id;
Basically what we're doing here is telling PDO to store a query that we've prepared in the $statement variable. We then tell it to use bindParam() to replace or bind :username with the POST variable (this will take care of escaping).
After the statement is executed using execute(), we have two options. The fetch() function essentially takes the next (or in this case, first) returned row and stores it in the $result variable. After that, you can access the returned columns using their names, in this case, $result->user_id. However if you SELECTed the rank, for example, you would be able to access it with $result->rank.
The second option is the fetchAll() function which works in nearly the same way, except that it takes every row returned and stores it in an array. Even if only one row is returned. That means that you'd need to access the data using $result[0]->user_id where 0 is the returned row.
foreach($result as $row){
echo $row->user_id;
}
Or you can loop over the result array using foreach as above. One of the greatest features of PHP in my opinion.
Updating and inserting works in nearly the same way except that no rows are returned by the execute function. Instead, the amount of rows that were changed is returned.
$statement = $database->prepare("
UPDATE tbl_users
SET email = :email
WHERE user_id = :user_id
");
$statement->bindParam("email", $_POST['email'], PDO::PARAM_STR);
$statement->bindParam("user_id", $_POST['account'], PDO::PARAM_INT);
$statement->execute();
echo "Rows changed: ".$statement->rowCount();
In that example, we're just updating the user's email address using a POST variable for the email and the account variable for the user_id. Notice that I used PDO::PARAM_INT for the third parameter of bindParam, that's just because the user_id is an integer. Usually you can get away with PDO::PARAM_STR but it's supposed to be for strings.
If you want a bit more detail by somebody far better at explaining things than me, check this introduction to PDO out. Hope this gets you on the right track!
So I'm making my own blog scripts using MYSQL and PHP.
I had the whole 'writing the blog to a database' thing working perfectly, until I realised that if you tried to write a blog with speech marks, this would prevent the INSERT statement from working (obviously - the speechmarks were ending the SQL statement).
So I tried to use real_escape_string, and now the INSERT doesn't work even if you exclude quotes.
I tried using:
sqlstate
in order to find out the issue, and it returned "42000" - which, after googling for a little bit, refers to a syntax error, which doesn't make much sense as there is no syntax error before the use of real_escape_string.
Also, I'm now getting this error:
Call to a member function close() on a non-object in /postarticle.php on line 37
Which refers to the close() call in the ELSE statement.
Please may you help? Been going round in circles for a while. Here is my code:
<?php
$host = 'CENSORED';
$user = 'CENSORED';
$pass = 'CENSORED';
$db = 'CENSORED';
$connection = new mysqli($host,$user,$pass,$db);
$_SESSION["article"] = $_POST["article"];
$date_of_blog = getdate();
$article = ($_SESSION["article"]);
$sql1 = "SELECT * FROM `Blogs`";
$res1 = $connection->query($sql1);
$newrows = $res1->num_rows + 1;
$sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES ('$newrows','$article','$date_of_blog')";
$sql2 = $connection->real_escape_string($sql2);
$res2 = $connection->query($sql2);
if ($res2->num_rows == $newrows)
{
$res->close();
$connection->close();
header( 'Location: adminpanel.php' );
}
else
{
echo ($connection->sqlstate);
$connection->close();
$res->close();
}
exit();
?>
Also, on a side note, the getdate() call that I've got has never worked. In the database every blog post comes up as:
0000:00:00 00:00:00
EDIT:
Issue is now solved. Find the functional code below:
<?php
$host = 'CENSORED';
$user = 'CENSORED';
$pass = 'CENSORED';
$db = 'CENSORED';
$connection = new mysqli($host,$user,$pass,$db);
$_SESSION["article"] = $_POST["article"];
$article = ($_SESSION["article"]);
$article = $connection->real_escape_string($article);
$sql1 = "SELECT * FROM `Blogs`";
$res1 = $connection->query($sql1);
$newrows = $res1->num_rows + 1;
$sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES (\"$newrows\",\"$article\",CURDATE())";
$res2 = $connection->query($sql2);
if ($res2 != false)
{
header( 'Location: adminpanel.php' );
}
else
{
echo ($connection->sqlstate);
}
$connection->close();
$res->close();
exit();
?>
I'm very sorry if these questions are basic and annoy the professionals around here; I've tried to follow the guidelines and I've googled for a while etc. I just haven't found any solutions that match my issue(s).
Thankyou for your time.
There are a number issues with the code as originally posted. Chiefly, the cause of the two issues you initially identified is a misuse of mysqli::real_escape_string(). It needs to be called on each variable individually which appears in the code. So instead of calling it on the whole statement, it must be called multiple times for multiple variables like:
$article = $connection->real_escape_string($connection);
The failure of the query due to incorrect quoting (due to real_escape_string()) is the reason for the error message calling close().
As ascertained in the comments, you are using num_rows + 1 to validate that one new row has been inserted based on the previous number of rows returned. This is problematic for a few reasons. Mainly, it exposes a race condition wherein a row may be inserted from two sessions at once and one or both will fail because the expected value for $newrows doesn't match. Really BlogID should be an auto_increment column in your database. That eliminates the need for any logic around it whatsoever. You don't even need to include it in the INSERT because it will be automatically incremented.
That also completely eliminates the need for the first SELECT statement.
Substituting MySQL's native NOW() function for the date value, you can simplify the statement to:
INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES ('$article', NOW())
To test success or failure of the insert, you just need to verify that its variable is not false.
Putting this together, your code can be reduced as:
if (!isset($_POST['article'])) {
// exit or handle an empty post somehow...
}
$connection = new mysqli($host,$user,$pass,$db);
$_SESSION["article"] = $_POST["article"];
// Escape $article for later use
$article = $connection->real_escape_string($_SESSION["article"]);
// Only an INSERT is needed. $article is already escaped
$sql = "INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES ('$article', NOW())";
// Run the query
$res = $connection->query($sql);
// Test for failure by checking for a false value
if ($res) {
// The connection & resource closure can be omitted
// PHP will handle that automatically and implicitly.
header( 'Location: adminpanel.php' );
// Explictly exit as good practice after redirection
exit();
}
else {
// The INSERT failed. Check the error message
echo $connection->error;
}
This should bring your current code into working order. However, since you're learning this it is an excellent time to begin learning to use prepared statements via prepare()/bind_param()/execute() in MySQLi. This is a recommended best practice to prevent SQL injection, although using real_escape_string() works as long as you use it correctly and never forget.
See How can I prevent SQL injection in PHP for examples.
But it would look like:
// connection already established, etc...
// Prepare the statement using a ? placeholder for article
$stmt = $connection->prepare("INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES (?, NOW())");
if ($stmt) {
// bind in the variable and execute
// Note that real_escape_string() is not needed when using
// the ? placeholder for article
$stmt->bind_param('s', $_SESSION['article']);
$stmt->execute();
// Redirect
header( 'Location: adminpanel.php' );
exit();
}
else {
echo $connection->error;
}
You need to apply the real_escape_string function to the variables not the entire SQL string.
$sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES ('".$connection->real_escape_string($newrows)."','".$connection->real_escape_string($article)."','".$connection->real_escape_string($date_of_blog)."')";
The purpose is to remove anything that might be misinterpreted as query functions by MySQL, but there are parts of the query that you obviously want to be interpreted as such.
I am trying to convert some old PHP ODBC queries over to PDO Prepared statements and am getting an error I cannot find too much information on.
The Error is:
"[DataDirect][ODBC Sybase Wire Protocol driver][SQL Server]There is no host variable corresponding to the one specified by the PARAM datastream. This means that this variable '' was not used in the preceding DECLARE CURSOR or SQL command. (SQLExecute[3801] at ext\pdo_odbc\odbc_stmt.c:254)"
I am searching for a single row in the database using a 6 digit ID that is stored in the database as a VARCHAR but is usually a 6 digit number.
The database connection is reporting successful.
The ID passed by the query string is validated.
The prepared statement results in the above error.
The backup straight ODBC_EXEC statement in the else clause returns the data I am looking for.
//PDO Driver Connect to Sybase
try {
$pdo = new PDO("odbc:Driver={Sybase ASE ODBC Driver};NA=server,5000;Uid=username;Pwd=password;");
$pdo_status = "Sybase Connected";
} catch(PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
if((isset($_GET['id'])) AND ($_GET['id'] != "")) {
//Validate ID String
if(!preg_match("/^[A-Za-z0-9]{5,7}/",$_GET['id'])) {
$query1_id = FALSE;
echo "Invalid ID";
exit;
} else {
$query1_id = $_GET['id'];
}
$query1 = $pdo->prepare("SELECT * FROM People WHERE PersonId= ?");
$query1->execute(array($query1_id));
if($query1->errorCode() != 0) {
$person_data = $query1->fetch(PDO::FETCH_ASSOC);
echo "Person Data from PDO: ";
print_r($person_data);
} else {
$errors = $query1->errorInfo();
echo $errors[2];
//Try the old way to confirm data is there.
$odbc_query1 = "SELECT * FROM People WHERE PersonId='$query1_id' ";
$person_result = odbc_exec($conn,$odbc_query1) or die("Error getting Data, Query 1");
$person_data = odbc_fetch_array($person_result);
echo "Person Data from ODBC_EXEC: ";
print_r($person_data);
}
It also fails if I use:
$query1 = $pdo->prepare("SELECT * FROM People WHERE PersonId= :id ");
$query1->execute(array(":id"=>$query1_id));
Does anyone have experience with this error?
Edit: Sybase Manual says this about the error...
Error 3801: There is no host variable corresponding to the one specified by the PARAM datastream. This means that this variable `%.*s' was not used in the preceding DECLARE CURSOR or SQL command.
Explanation:
Adaptive Server could not perform the requested action. Check your command for missing or incorrect database objects, variable names, and/or input data.
Which is odd because my error (quoted at the top) doesn't tell me which variable has no host.
Also fails if I use...
$query1 = $pdo->prepare("SELECT * FROM People WHERE PersonId= :id ");
$query1->bindParam(':id',$query1_id,PDO::PARAM_STR); //Or PARAM_INT
$query1->execute();
The query works if I place the variable in the query like this...
$query1 = $pdo->prepare("SELECT * FROM People WHERE PersonId= '$query1_id'");
So I think it has something to do with the parameter not being bound to the placeholder but I can't figure out why.
If I can't work this out I'll have to revert to building my query as a string and hoping my input validation is bullet proof.
Your problem seems to be with the default data type PHP assigns to variables in the placeholders. The SQL Statement is looking for a number but PHP is interpreting it as something else. You can prevent this using quotes around the placeholder variable. Notice that in the statements that work you have apostrophes ('') around the value that PHP sees:
$query1 = $pdo->prepare("SELECT * FROM People WHERE PersonId= '$query1_id'");
Try this when using the placeholder it should be the same:
$query1 = $pdo->prepare("SELECT * FROM People WHERE PersonId= ':id'");
What's the correct way to code the following
SELECT * FROM table WHERE value = $row['item']
$row['item'] echos correctly, but does not seem to work in the mysql query. Been having this problem for a few days. I've tried .$row['item']. and a few other variations but I must be doing something wrong.
The better more appropriate approach is to use mysqli and prepared statements ie:
$stmt = $mysqli->prepare("SELECT * FROM table WHERE value =?");
$stmt->bind_param("s",$row['item']); // I am assuming row['item'] is a string
$stmt->execute();
If you can't use mysqli or absolutely refuse to you can use this:
$query = "SELECT * FROM table WHERE value = '".mysql_real_escape_string($row['item'])."'";
The answer sort of depends on what is held within the $row['item'] variable. If it's a numeric value, then the query above should be fine. Since it's not working, I assume that the value of that variable is actually a string. In that case, you need to surround the value in quotes so that the database can correctly identify it as a string value (otherwise, it would just be gibberish "commands" that the database can't identify, causing the query to fail).
Regardless of the above, you shouldn't be directly inserting variables into a query under pretty much any circumstances. The reason is that it opens you up to SQL injection if you're not extremely careful. For example, if your $row['item'] variable was wrapped in single quotes in the query, but contained a single quote in its value, then the database would interpret the quote within the variable as the ending quote for the entire parameter, and it would screw up the query. Worse still, a hacker could take advantage of this to end your query entirely, then add a second query of his own making onto it (or they could introduce a UNION query on the end of the original, etc.). At the very least, you should be running something like mysql_real_escape_string() on the variable before using it:
$sql = "SELECT * FROM table WHERE value = " .
mysql_real_escape_string($row['item']);
The best way to get around this and secure your queries is to use prepared statements. These are queries that have placeholders in them instead of concatenated variables. You prepare the query with these placeholders, then you issue additional commands to the database to tell it what values to place in those placeholders. The database then takes care of the tricky issue of sanitizing these variables so that they don't cause any damage. You can use PDO for this:
try {
$dbh = new PDO(DB_DSN,
DB_USER,
DB_PASS,
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
exit();
}
// create query with a named placeholder
$sql = "SELECT * FROM table WHERE value = :value";
try {
$stmt = $dbh->prepare($sql);
// tell PDO to substitute the value in $row['item']
// for the named parameter specified above.
$stmt->bindValue(":value", $row['item']);
// execute the query and load the results into an array
$stmt->execute();
$records = $stmt->fetchAll();
} catch (PDOException $e) {
echo "Query failed: " . $e->getMessage();
exit();
}
foreach ($records as $record) {
// use db records
}
The way I usually recommend doing it is something like this:
$sql = sprintf("SELECT * FROM table WHERE value = '%s'",
mysql_real_escape_string($row['item']));
$item = mysql_real_escape_string($row['item']);
$mysqlQuery = "SELECT * FROM table WHERE value = '" . $item . "'";
you are missing single quotes
SELECT * FROM table WHERE value = '{$row['item']}'
PHP example
I am trying to insert values in database and values are not being inserted, here is the code i have:
$user_name = "username";
$password = "password";
$database = "database";
$server = "localhost";
$db_handle = mysql_connect($server, $user_name, $password);
$db_found = mysql_select_db($database, $db_handle);
if ($db_found) {
$SQL = 'INSERT INTO table (anInt, DomainName, URL, Rank, PageRank, Google, Bing, Boss, IndexedPage, Backlinks) VALUES ($anInt, $Domain, $URL, $Rank, $Pagerank, $Google, $Bing, $Yahoo, $Pages, $backlinks)';
$result = mysql_query($SQL);
mysql_close($db_handle);
print "Records added to the database";
it is printing that records added to the database but when looking at the database nothing is being added. some of the values are doubles, text, and ints. Is there anyway to debug this? I will be adding more information to the post if someone asks me to.
and of course I have an else statement i just thought it is not relevant since it is telling me that records are added.
First of all, you should escape the string values you are passing into the SQL query, using mysql_real_escape_string.
Then, you should add quotes, in your SQL query, arround the fields that are meant to contain strings.
I don't really know which fields are integers and which fields are strings, but you should be using something like this to build your SQL query :
// Escape the string data, and make sure integer really contain integers
$anInt = intval($anInt);
$Domain = mysql_real_escape_string($Domain);
$URL = mysql_real_escape_string($URL);
$Rank = intval($Rank);
$Pagerank = = intval($Pagerank);
$Google = intval($Google);
$Bing = intval($Bing);
$Yahoo = intval($Yahoo);
$Pages = intval($Pages);
$backlinks = intval($backlinks );
// Build the SQL query, using the "safe" variables
$SQL = 'INSERT INTO table (anInt, DomainName, URL, Rank, PageRank, Google, Bing, Boss, IndexedPage, Backlinks)
VALUES ($anInt, '$Domain', '$URL', $Rank, $Pagerank, $Google, $Bing, $Yahoo, $Pages, $backlinks)';
This is supposing that only DomainName and URL are meant to contain strings -- you might have to use mysql_real_escape_string and add quotes arround the values for some other fields too, if needed.
Then, you should take a look at the return value of mysql_query : for an insert query, in case of an error, it'll return false.
Here, if your $result variable is false, you should use mysql_error and mysql_errno : they'll allow you to know what error happened -- it will help detecting errors in your SQL query, for instance.
If this doesn't solve the problem, you should try outputting the SQL query, and run it using something like phpMyAdmin, to make sure it's OK.
I am no PHP expert, but I have 2 remarks.
You don't check the error (perhaps with mysql_errno()) so you don't know whether the records were added
I think the values, if they are strings, should be given like
'$Domain'
that is, escaped with ' characters.
better would be, of course, using something like
$sql = sprintf("INSERT ... VALUES(%d, '%s', '%s',...)",
$anInt, mysql_real_escape_string($Domain), ...);
if you insert user-supplied input.
You could examine the $result:
$result = mysql_query($query);
if (!$result) {
print "An error occured: " . mysql_error() . "\n";
}
My guess is that you're passing a string without quotes, like:
VALUES (Hello)
where you should pass it like:
VALUES ('Hello')
Like the commenter said, if the user can control these strings, you are open to an SQL Injection attack. You can prevent that attack by escaping the strings, for example:
$query = sprintf("INSERT INTO table (DomainName) VALUES ('%s')",
mysql_real_escape_string($domain_name));
In SQL queries, you need to enquote strings correctly, or it will produce an error. So all your variables that are used to store non-int or non-boolean values in the database need quotes around the values.
Additionally you should make sure that SQL injections are not a problem by escaping all values with mysql_real_escape_string first.
Apart from sql injections your error handling is not complete...
if (!$db_found) {
echo "datbase not found.";
}
else {
$SQL = 'INSERT INTO
table
(...)
VALUES
(...)
';
$result = mysql_query($SQL, $db_handle);
if ( !$result ) {
echo "error: ", mysql_error($db_handle);
}
else {
print "Records added to the database";
}
}
mysql_close($db_handle);
In case a query causes an error mysql_query() return FALSE and mysql_error() will tell you more about the error.
Well there are security issues with the code but to address one problem
you are not enclosing your string values in quotes in the SQL statement.
First of all, please regard everybody else's advice on safe database handling and avoiding injection.
The reason your query isn't doing anything is probably that you enclosed the string in single quotes. In PHP single quotes enforce the string to be literal. Unlike when using double quotes, variables will NOT be substituted. So '$foo' represents the sequence of characters '$'.'f'.'o'.'o'. "$foo" on the other hand represents the sequence of characters of whatever the variable $foo contains at the time of the string's definition.
You can use mysql_error() to catch most problems with MySQL. Even if the message isn't helping you, you at least know whether the query was parsed properly, i.e. on which end of the connection the problem lies.