This works:
$row = mysql_fetch_array($result);
$accountID = $row['accountID'];
queryMysql('INSERT INTO accounts (accountID, password) VALUES (' .
"'$accountID'" . ', \'a\')');
But this doesn't:
$row = mysql_fetch_array($result);
queryMysql('INSERT INTO accounts (accountID, password) VALUES (' .
$row['accountID'] . ', \'a\')');
Why?
Because you're missing another ' right before and after $row['accountId']
$row = mysql_fetch_array($result);
queryMysql('INSERT INTO accounts (accountID, password) VALUES (\'' .
$row['accountID'] . '\', \'a\')');
If you are beginning PHP and have the required version of PHP (5.1.0) I strongly suggest you start using PDO
http://php.net/pdo
instead of the standard mysql_*
First, you should always tell us why it doesn't work. Only saying "it doesn't work" is really begging for getting your post ignored.
Second, the cause of the error is most likely the lack of quote, but that would only be necessary if there's another underlying problem. The type of the column accountID seems to be varchar or text. An ID should be an integer.
You have to wrap your value with quotes if it's a string, you don't if it's an integer.
Related
I am writing a php script to put a dictionary file into a Mysql database. It works fine, except in certain cases when the definition strings contain both single quotes and multiple sets of curly braces. This is one of the definition strings that fails.
(n) (1) {sports} carry-back/bringing the ball back to one's own
position (in rugby)/(2) {econ} carryback/carrying over a deduction or
credit from a prior year to the current year (to reduce income tax)
This is the **MySQLi ** error message:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 's own position (in rugby)/(2) econ', {'(n) (1) {sports}
carry-back/bringing the ' at line 1
Heres the section of the script regarding the definition string:
$definition = substr($definition_string, 0, $pos);
$definition = substr($definition, 1);
// Escape single quote
$definition = str_replace(["'"], "''" , $definition);
$mysqli->set_charset("utf8");
$result = $mysqli->query("INSERT INTO dict (entry, reading, category, definition, entry_number) VALUES ('$entry', '$reading', '$category', '$definition', '$entry_number')");
I can't figure out why its failing and the error message isn't helping much. Any ideas?
I recommend you read about this here. They give several different methods on how to protect the data going into the database.
Here is one of the many ways:
$result = $mysqli->query("INSERT INTO dict (entry, reading, category, definition, entry_number) VALUES (
'" . $mysqli->escape_string($entry) . "',
'" . $mysqli->escape_string($reading) . "',
'" . $mysqli->escape_string($category) . "',
'" . $mysqli->escape_string($definition) . "',
'" . $mysqli->escape_string($entry_number) . "')");
Another more eloquent solution:
$stmt = $mysqli->prepare("INSERT INTO dict (entry, reading, category, definition, entry_number) VALUES (
?, ?, ?, ?, ?)");
$stmt->bind_param('sssss', $entry, $reading, $category, $definition, $entry_number);
$stmt->execute();
$result = $stmt->get_result();
I'm having hard time to figure out whats wrong in this code. I tried many variations but still getting error in this line:
$query= "INSERT INTO publish (name, email, title, content)" .
"VALUES ('$row['Name']','$row['Email']',$row['title'],$row['content'])";
What could be wrong?
here's the rest of the code:
<?php
// connect to the database
include('config2.php');
// check if the 'id' variable is set in URL, and check that it is valid
if (isset($_GET['id']) && is_numeric($_GET['id']))
{
// get id value
$id = $_GET['id'];
$dbc = mysqli_connect('localhost', 'x', 'x', 'x')
or die('Error');
$name = $row['Name'];
$email = $row['Email'];
$title = $row['title'];
$content = $row['content'];
$result = mysql_query("select *stories WHERE id=$id")
or die(mysql_error());
$row = mysql_fetch_array( $result );
$query= "INSERT INTO publish (name, email, title, content)" .
"VALUES ('$row['Name']','$row['Email']',$row['title'],$row['content'])";
or die('Error querying database.');
mysqli_close($dbc);
}
?>
Error message: "parse error expecting identifier (t_string) ' or variable (t_variable) ' or number (t_num_string) '"
You probably want to use complex string syntax to properly interpolate those variables. For example:
$query= "INSERT INTO publish (name, email, title, content)" .
"VALUES ('{$row['Name']}','{$row['Email']}',{$row['title']},{$row['content']})";
Though that will only fix one of the issues with the code.
Do note there are plenty of other ways to resolve this one too, such as concatenation instead of interpolation, or string replacements, etc etc.
It might also be worth reading the documentation on strings at some point.
You forgot the "." between your variables and your strings. Like so:
$query= "INSERT INTO publish (name, email, title, content)" .
"VALUES (".$row['Name'].','.$row['Email'].','.$row['title'].','.$row['content'].")";
However, it looks like you may have some additional issues going on there with the actual SQL query.
The best practice in PHP is to use single quote ' for strings. Cos PHP looks for variables inside double quoted strings and keeps on sniffing whether there is a variable (or multiple variables) inside the string.
So for example: "A very very long string... $var1 .. long string .. $var2 string" this will run slower compared to 'A very very long string... ' . $var1 . ' .. long string .. ' . $var2 . ' string'; cos when PHP sees single quote it won't sniff for variables inside it thus it's faster.
From my experience, in my early age I worked on a very large php script and used double quotes everywhere. After the above explanation from an expert I converted the whole script to single quote and the performance was much better.
So for your situation I'd suggest and request to use single quotes and it'll avoid confusions as well. Also using mysql_real_escape_string() is a good practice to avoid SQL Injection.
$query= 'INSERT INTO publish (name, email, title, content)
VALUES (
\'' . mysql_real_escape_string ($row['Name']) . '\',
\'' . mysql_real_escape_string ($row['Email']) . '\',
\'' . mysql_real_escape_string ($row['title']) . '\',
\'' . mysql_real_escape_string ($row['content']) . '\')';
I have been wondering on this question for a while. I have two PHP programs that are almost exactly identical except for the fact that on of them is a function and the other isn't. Furthermore one works and the other send back the error:
Call to a member function fetch_object() on a non-object
I fixed the one that wasn't working by omitting the variables and inserting definitive strings and adding $con->errno instead of mysqli_errno. However, when I replaced the strings with the variables again the problem returned.
So, my question is: what causes this error and how would I fix it. Also, why is the error coming up in the second code and not the first?
The First Code (works)
<?php
$con = new mysqli("database info");
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$stmt = $con->query("SELECT coordinator, announcements, description, comments, picture FROM Class_data WHERE class_year = '" .$class. "';");
$result_row = $stmt->fetch_object();
$coordinator = $result_row->coordinator;
$announcement = $result_row->announcements;
$description = $result_row->description;
$comments = $result_row->comments;
$picturepath = $result_row->picture;
mysqli_error($con);
mysqli_close($con);
if ($picturepath == "")
{
$picturepath = "../images/AlumnLogo.png";
}
?>
Second Code (doesn't work)
<?php
function fetch($page, $content1, $content2, $content3)
{
$con = new mysqli("database info");
if ($con->errno)
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$stmt = $con->query("SELECT '" .$content1. "' , '" .$content2. "' , '" .$content3. "' FROM '" .$page. "';");
$result_row = $stmt->fetch_object();
$content = array();
$content[0] = $result_row->body;
$content[1] = $result_row->calendar;
$content[2] = $result_row->announcements;
$output = implode("--",$content);
mysqli_error($con);
mysqli_close($con);
return $output;
}
?>
Thanks alot!
You are quoting your column names using single quotes. You cannot do that, you need to quote table- and column names using backticks (in case of reserved words, spaces, etc.) and only (non-integer...) values need to be quoted using single or double quotes.
Change your code to:
$stmt = $con->query("SELECT `" .$content1. "` , `" .$content2. "` , `" .$content3. "` FROM `" .$page. "`;");
^ All these
By the way, I assume you are using a white-list for your table- and column names. If not, you should to avoid sql injection.
It is also a good idea to add error handling to your database calls. An easy way using mysqli, is to put mysqli_report(MYSQLI_REPORT_STRICT); at the start of your script. This will cause mysqli to throw exceptions so that you do not have to check for individual errors on each database call.
The error message simply means that you try to call a method on something that is not an object. The problem is that $stmt is not an object!
This happens because there is an error in your SQL Statemetn. $con->query() retuns false in such a case. Therefore, what you try to execute is something like false->fetch_object();. And false isn't an object...
Try to print your generated SQL Statement. It will probabely contain some syntax errors. Fix those, and it will work
I am converting from extension mysql to PDO and after reading all I could from you gurus in SO and elsewhere, I have some residual doubts. I came up with the following to address sql injection for a typical query. I am just wondering if that's enough or may be I am going a bit overboard with the whitelisting, before I replicate this to all my application.
It's not clear to me if I did the whitelisting properly, ie, if I should also escape somehow.
Also, I am not sure if I should setAttribute emulate to false for every query or just once for the script.
$link = new PDO("mysql:host=$hostname;dbname=$database;charset=utf8", $username, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$arr_i=$arr_k='';
$m_act=$v_act='Y';
$table = array('prices', 'versions', 'models');
$allowedTables = array('prices', 'versions', 'models');
$field = array('model_id', 'version_id', 'price', 'models.active', 'versions.active');
$allowedFields = array('model_id', 'version_id', 'price', 'models.active', 'versions.active');
if(count( array_diff($field, $allowedFields))==0 AND count( array_diff($table, $allowedTables))==0){
$sql = "SELECT COUNT(DISTINCT `" . $field[0] . "`) as ctmod FROM `" . $table[0] . "`
INNER JOIN `" . $table[1] . "` USING (`" . $field[1] . "`)
INNER JOIN `" . $table[2] . "` USING (`" . $field[0] . "`)
WHERE `" . $field[2] . "` BETWEEN :arr_i AND :arr_k
AND " . $field[3] . " = :m_act
AND " . $field[4] . " = :v_act";
$stmt = $link->prepare($sql);
$stmt->bindParam(':arr_i', $arr_i, PDO::PARAM_INT);
$stmt->bindParam(':arr_k', $arr_k, PDO::PARAM_INT);
$stmt->bindParam(':m_act', $m_act, PDO::PARAM_STR);
$stmt->bindParam(':v_act', $v_act, PDO::PARAM_STR);
for ($i=0; $i < $ctpri; $i++){
$k=$i+1;
$arr_i=$arr_pri[$i]+1;
$arr_k=$arr_pri[$k];
$stmt->execute();
while ($r = $stmt->fetch(PDO::FETCH_ASSOC)) {
$ctmod[] = $r['ctmod'];
}
}
}
else{die();}
I suspect that you indeed going a bit overboard with the whitelisting. And not only with whitelisting but even with prepared statements too. And to satisfy your wrong views, you over-engineered your query to the point of totally uncomprehensible mess.
What you need to understand is that any constant value is safe by design. So, there is absolutely no point in using nor whitelisting nor prepared statements for it.
So, instead of
AND " . $field[3] . " = :m_act
you should write just
AND versions.active = 'Y'
without any binding or whitelisting.
All you need to protect is dynamical values only. So, you have to use prepared statements for $arr_i and $arr_k only. All other query parts have to be written into query directly, just like you did it before.
Yes, your code is thoroughly safe from SQL injection. Good job.
Though as #YourCommonSense points out, there's no reason in the example you show to make table and columns names into variables at all. It would be simpler to just write them into the query literally.
Therefore, I assume you're asking this question because you do sometimes choose table and column names through application logic or variables, even though you haven't shown it in this particular example.
The only tips I would offer are:
All the string concatenation, with ending double-quotes, using . and re-starting double-quotes makes the code look untidy and it can be confusing to keep track of which double-quotes you've started and stopped. An alternative style of PHP string interpolation for variables is to enclose in curly braces, like the following:
$sql = "SELECT COUNT(DISTINCT `{$field[0]}`) as ctmod FROM `{$table[0]}`
INNER JOIN `{$table[1]}` USING (`{$field[1]}`)
INNER JOIN `{$table[2]}` USING (`{$field[0]}`)
WHERE `{$field[2]}` BETWEEN :arr_i AND :arr_k
AND `{$field[3]}` = :m_act
AND `{$field[4]}` = :v_act";
And for yet another alternative, you can use here documents, so you don't have to worry about delimiting the string at all. Nice if you have literal double-quotes inside your string, because you don't have to escape them:
$sql = <<<GO
SELECT COUNT(DISTINCT `{$field[0]}`) as ctmod FROM `{$table[0]}`
INNER JOIN `{$table[1]}` USING (`{$field[1]}`)
INNER JOIN `{$table[2]}` USING (`{$field[0]}`)
WHERE `{$field[2]}` BETWEEN :arr_i AND :arr_k
AND `{$field[3]}` = :m_act
AND `{$field[4]}` = :v_act
GO;
Finally, it has nothing to do with SQL injection, but a good practice is to check the return value from prepare() and execute(), because they return false if an error occurs in parsing or execution.
if (($stmt = $link->prepare($sql)) === false) {
trigger_error(PDO::errorInfo()[2], E_USER_ERROR);
}
(That example uses PHP 5.4 syntax to dereference an array returned from a function.)
Or else you can configure PDO to throw exceptions, so you don't have to check.
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
I am trying do multi-driver support for my Framework, which basically means I can use MySQL, MySQLi or PDO(MySQL) with ease.
So, let's say I have an array of values I want to insert.
array('Manuel', 'StackOverflow');
and I have this query..
mysql_query("INSERT INTO users(name, fav_site) VALUES(?, ?)");
So, I'd like to replace the question marks with those values in order, so Manuel goes first and then goes StackOverflow. Remembering that I need to add -> ' <- at the sides of these values so MySQL doesn't throw an error.
I have tried searching if someone has asked this and had no luck.
Any help is appreciated!
NOTE: I know I shouldn't even bother with MySQL, but hey! A feature is a feature.
<?php
$query = "INSERT INTO users(name, fav_site) VALUES(?, ?)";
$args = array('joe', 'google goggles');
while(strpos($query, '?') !== FALSE)
{
$query = preg_replace('/\?/', your_quoting_func(array_shift($args)), $query, 1);
}
echo $query;
Basically, this says...while there is still a ? remaining in the string, delete the first question mark and replace it with a quoted (use your own function or mysql_real_escape_string and surround with single quotes) string, and shift that item off the array. You should probably substr_count the ? marks versus the number of arguments for error checking.
I used preg_replace because it accepts an argument specifying how many values to replace, whereas str_replace does not.
I would do it this way (with one exeption: I wouldn't use mysql_):
<?php
$values = array('foo', 'bar');
$query_start = "INSERT INTO `users` (`name`, `fav_site`) VALUES ('";
$query_end = "')";
$query = $query_start . implode("', '", $values) . $query_end;
$result = mysql_query($query);
?>
$query_start contains the start of the MySQL query (notice the ' at the end), and $query_end goes at the end.
Then $values is imploded, with ', ' as the 'glue', and $result is set as:
$query_start (impoded $result) $query_end.
See implode - PHP Manual.