I am having an issue with this not running at all when the information is submitted, I believe that I have the syntax wrong.
if ($_POST['note'] != $player->note_text) {
$message = 'Admin '.$user.' has added the note ('.$_POST['note'].') to '.$player->name.'('.$pid.')';
logIt($user, $message, $dbcon);
$note = $_POST['note'];
$note = '"'.$note.'"';
$UpdateN = "INSERT INTO notes (uid, staff_name, name, alias, note_text, warning) VALUES ('$_POST[hidden]', '$user', '$player->name', '$player->aliases', '$note','$_POST[warn]')";
$UpdateN2 = "INSERT INTO players WHERE `playerid` = $_POST[hidden] (warning) VALUES ('$_POST[warn]')";
mysqli_query($dbcon, $UpdateN, $UpdateN2);
The new line I added which seems to have broken it is '$UpdateN2'.
I am not sure if the new line has broken the statement, since I am new to PHP and mysqli any pointers to forums or websites that I can learn and understand this in a more detailed way I would appreciate.
Edit: I have since moved from using mysqli to PDO, I strongly suggestion that anyone willing to start using MYSQL commands with PHP to have a look at this: http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
I started reading this and testing things out, I find this much more easier but also it looks a lot cleaner and understandable when reading it back after a few days have passed.
In keeping with the mysqli procedural style in the original, using prepared statements with bind placeholders, something like this:
$UpdateN = 'INSERT INTO notes (uid, staff_name, name, alias, note_text, warning)'
. ' VALUES ( ?, ? , ? , ? , ? , ? )';
$UpdateN2 = 'UPDATE players SET warning = ? WHERE playerid = ? ';
if( $sth = mysqli_prepare($dbcon,$UpdateN) ) {
mysqli_stmt_bind_param($sth,'ssssss'
,$_POST['hidden']
,$user
,$player->name
,$player->aliases
,$_POST['note']
,$_POST['warn']
);
if( mysqli_stmt_execute($sth) ) {
// statement execution successful
} else {
printf("Error: %s\n",mysqli_stmt_error($sth));
}
} else {
printf("Error: %s\n",mysqli_error($dbcon));
}
if( $sth2 = mysqli_prepare($dbcon,$UpdateN2) ) {
mysqli_stmt_bind_param($sth2,'ss'
,$_POST['warn']
,$_POST['hidden']
);
if( mysqli_stmt_execute($sth2) ) {
// statement execution successful
} else {
printf("Error: %s\n",mysqli_stmt_error($sth2));
}
} else {
printf("Error: %s\n",mysqli_error($dbcon));
}
If it was me, I'd just make two separate calls to mysqli_query, one for each of your separate queries. PHP has historically been very wary of permitting multiple queries in a single function call, because of possible sql injection vulnerabilities.
On a related note, you need to sanitize your input. $_POST should never, ever, ever appear directly in a mysql query string, because your post data might -actually be something like ')"; DROP TABLE users;'.
Finally, you're using a WHERE clause on an insert. That's probably breaking your query. You should take a couple of days and research how and why that's breaking your query, and how and why to write proper sql queries. Doing so will add value to your company, because your company is less likely to suffer a catastrophic data breach, and it will add value to you, because you'll be a better SQL coder.
Edit: and in the time it took me to write this, three different people made each of those points. LOL.
Related
Good day,
First off I'm an I.T starting to get into coding, so please be gentle ^^.
So currently I'm building a script where it takes input (Nexmo) and sends it to my database.
Sadly LOTS of blank spaces seem to be filling up my database. For some reason I can't seem to be able to filter out these nulls?
Would anyone be willing to help?
Thanks!
Heres the code
require('db.php');
if (!$connect) {
die('Could not connect: ' .mysql_error());
}
$sql = "INSERT INTO `INCOMING` (`TO`, `TEXT` , `FROM`, `MESSAGEID`) VALUES ('$_GET[to]','$_GET[text]' ,'$_GET[msisdn]' , '$_GET[messageId]')";
if (!mysql_query($sql)){
die('Error: ' . mysql_error());
}
else {
echo "TO";
}
mysql_close();
Welcome to StackOverflow and to programming!
First of all, I get that you're learning but I'm going to be hard on you to help you. You've got a bad habit from a book or tutorial and I'm not going to let you learn it.
SQL Injection is the #1 vulnerability on OWASP. By inserting data directly from the request (i.e., $_GET) into a SQL query, you are exposing this vulnerability. At the very minimum, escape the data first before integrating with the query
$to = mysql_real_escape_string($_GET['to']);
$text = mysql_real_escape_string($_GET['text']);
$msisdn = mysql_real_escape_string($_GET['msisdn']);
$messageId = mysql_real_escape_string($_GET['messageId']);
$sql = "INSERT INTO `INCOMING` (`TO`, `TEXT` , `FROM`, `MESSAGEID`) VALUES ('$to','$text' ,'$msisdn' , '$messageId')";
I know it looks like more work but good programming is not about saving yourself keystrokes. That being said, you're much better off switching to PDO and using parameterized queries. Besides, the mysql_* family of functions are deprecated.
Now - on to your actual problem. All incoming data needs to be validated and oftentimes filtered to match the business rules of your application. For example, if you want to require that all of these fields have at least one non-whitespace character, you'll need to enforce that. Building off the snippet from above:
function filterInput($value)
{
// Trim all leading/trailing whitespace and newlines
return preg_replace('/^[\s\r\n]+|[\s\r\n]+$/', $value);
}
function validateInput($value)
{
if (NULL === $value || '' === $value) {
return false;
}
return true;
}
// Filter input per your business rules
$to = filterInput($_GET['to']);
$text = filterInput($_GET['text']);
$msisdn = filterInput($_GET['msisdn']);
$messageId = filterInput($_GET['messageId']);
// Now verify they all have real values
if (validateInput($to) && validateInput($text) && validateInput($msisdn) && validateInput($messageId)) {
// Now escape for SQL
$to = mysql_real_escape_string($to);
$text = mysql_real_escape_string($text);
$msisdn = mysql_real_escape_string($msisdn);
$messageId = mysql_real_escape_string($messageId);
// Proceed with INSERT
}
And yet again, I'm sure you're thinking "holy cow that looks like a lot of work" because I took one line of your code and turned it into 20, but that's part of the deal with programming. It's also why people spend lots and lots of time writing libraries and frameworks to abstract-away a lot of this type of "grunt work" code.
Happy coding!
To make sure you don't send empty spaces to the database, you could replace
$sql = "INSERT INTO `INCOMING` (`TO`, `TEXT` , `FROM`, `MESSAGEID`)
VALUES ('$_GET[to]','$_GET[text]' ,'$_GET[msisdn]' , '$_GET[messageId]')";
with
if( !empty($_GET['to']) and !empty($_GET['text']) and !empty($_GET['msisdn']) and !empty($_GET['messageId']) ) {
$sql = sprintf("INSERT INTO `INCOMING` (`TO`, `TEXT` , `FROM`, `MESSAGEID`)
VALUES ('%s','%s' ,'%s' , '%s')",
trim($_GET['to']), trim($_GET['text']),
trim($_GET['msisdn']), trim($_GET['messageId']));
}
This way you'll have leading and trailing spaces, new-lines and other not-printable characters removed before the insert and the insert will only be executed if you have all the information.
Aside from that, the only thing to make sure is that your columns are not of type CHAR, as that would cause the empty spaces regarding of what you send from your code.
I'd also advise against sending information from the browser (GET) straight to the database as it could cause some serious security issues.
I generate the below query in two ways, but use the same function to insert into the database:
INSERT INTO person VALUES('','john', 'smith','new york', 'NY', '123456');
The below method results in CORRECT inserts, with no extra blank row in the sql database
foreach($_POST as $item)
$statement .= "'$item', ";
$size = count($statement);
$statement = substr($statement, 0, $size-3);
$statement .= ");";
The code below should be generating an identical query to the one above (they echo identically), but when I use it, an extra blank row (with an id) is inserted into the database, after the correct row with data. so two rows are inserted each time.
$mytest = "INSERT INTO person VALUES('','$_POST[name]', '$_POST[address]','$_POST[city]', '$_POST[state]', '$_POST[zip]');";
Because I need to run validations on posted items from the form, and need to do some manipulations before storing it into the database, I need to be able to use the second query method.
I can't understand how the two could be different. I'm using the exact same functions to connect and insert into the database, so the problem can't be there.
below is my insert function for reference:
function do_insertion($query) {
$db = get_db_connection();
if(!($result = mysqli_query($db, $query))) {
#die('SQL ERROR: '. mysqli_error($db));
write_error_page(mysqli_error($db));
} #end if
}
Thank you for any insite/help on this.
Using your $_POST directly in your query is opening you up to a lot of bad things, it's just bad practice. You should at least do something to clean your data before going to your database.
The $_POST variable often times can contain additional values depending on the browser, form submit. Have you tried doing a null/empty check in your foreach?
!~ Pseudo Code DO NOT USE IN PRODUCTION ~!
foreach($_POST as $item)
{
if(isset($item) && $item != "")
{
$statement .= "'$item', ";
$size = count($statement);
$statement = substr($statement, 0, $size-3);
$statement .= ");";
}
}
Please read #tadman's comment about using bind_param and protecting yourself against SQL injection. For the sake of answering your question it's likely your $_POST contains empty data that is being put into your query and resulting in the added row.
as #yycdev stated, you are in risk of SQL injection. Start by reading this and rewrite your code by proper use of protecting your database. SQL injection is not fun and will produce many bugs.
I have successfully gotten queries to execute and print in PDO, but I'm doing something wrong here. The important part of the code for this question is in the last couple blocks of code; I'm including the first portion just for clarity.
This code connects to an HTML form with multiple input fields. The PHP constructs a query by appending the data from each field with ANDs in the WHERE statement.
This is what throws me: I echo the $query variable, and I can see that the query is formed properly, but when I then try to print the query results, no results are printed.
I wrestled with using prepared statements here, and decided to try getting the code to work first without them after failing to construct a prepared statement with varying numbers of parameters. I did try, with the help of this post: LIKE query using multiple keywords from search field using PDO prepared statement
So, setting aside prepared statements for the moment, can anyone tell me what I'm doing wrong here? Any help would be greatly appreciated.
<?php
if(isset($_POST['submit'])) {
// define the list of fields
$fields = array('titleSearch', 'keywordSearch', 'fullSearch', 'fromYear', 'toYear',
'fromSeconds', 'toSeconds', 'withSound', 'withColor');
$conditions = array();
// loop through the defined fields
foreach($fields as $field){
// if the field is set and not empty
if(isset($_POST[$field]) && $_POST[$field] != '') {
// create a new condition, using a prepared statement
$conditions[] = "$field LIKE CONCAT ('%', $_POST[$field], '%')";
}
}
// build the query
$query = "SELECT keyframeurl, videoid, title, creationyear, sound, color,
duration, genre FROM openvideo ";
// if there are conditions defined, append them to the query
if(count($conditions) > 0) {
$query .= "WHERE " . implode(' AND ', $conditions);
}
//confirm that query formed correctly
echo $query;
//print query results
foreach ($dbh->query($query) as $row){
print $row['videoid'].' - '.$row['title'].'<br />';
}
}
?>
Instead of posting your query you have to run it.
That's the only way to fix the problem
a Stack Overflow passer-by do not have a database server in their head to run your query.
a Stack Overflow passer-by do not have your particular database server in their head to run your query.
So, you are the only one who can run your query against your database and ask it what's going wrong.
Turn on error reporting. Make sure sure you can see errors occurred. Try to add intentional error and see if it works.
Double-check your database data if it really contains desired values.
Double-check your input data, if it really match database values.
Run your assembled query against database in console or phpadmin.
Dig to some certain problem. Do not just sit and wait. Asking a question "I have a code it doesnt work" makes very little sense. Code have to be run, not stared into.
$conditions[] = "$field LIKE CONCAT ('%', $_POST[$field], '%')";
is the culprit: sending "something" for the title ends up in something like
WHERE titleSearch LIKE CONCAT('%', something, '%')
but you want
WHERE titleSearch LIKE CONCAT('%', 'something', '%')
with more quotes.
Be sure not to roll this out into production though, as you might end up with somebody posting "xxx') OR 1=1; --" just for the perofrmance fun, or even worse, depedning on their mood.
You've forgotten quotes around the $_POST values that you're directly inserting into your queries:
$conditions[] = "$field LIKE CONCAT ('%', '$_POST[$field]', '%')";
^-- ^--
so while this will fix your immediate problem, you'll still be wide open to sql injection attacks.
You don't even need the CONCAT built-in function, you can model the whole string as $conditions[] = "{$field} LIKE '%{$_POST[$field]}%'". But you should use prepared statements if you don't want to face serious SQL injection attacks in the short-term future.
Why don't you try something like this? (using PDO as an example):
if ($pdo = new \PDO("mysql:host=localhost;dbname=testdb;charset=utf8", "user", "password")) {
$fields = ["titleSearch","keywordSearch","fullSearch","fromYear","toYear","fromSeconds","toSeconds","withSound","withColor"];
$parameters = array_map(function ($input) { return filter_var($input, FILTER_SANITIZE_STRING); }, $fields)
$conditions = array_map(function ($input) { return (!empty($_POST[$input]) ? "{$input} LIKE ?" : null); }, $fields);
$query = "SELECT `keyframeurl`,`videoid`,`title`,`creationyear`,`sound`,`color`,`duration`,`genre` FROM `openvideo`" . (sizeof($conditions) > 0 ? " " . implode(" AND ", $conditions) : null);
if ($statement = $pdo->prepare($query, [\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY])) {
if ($statement->execute((!empty($parameters) ? $parameters : null))) {
$result = $statement->fetchAll(\PDO::FETCH_ASSOC);
}
}
}
Haven't tested it (just coming to my mind right now), but it should set up PDO, prepare a statement based on the conditions you seem to look for, add the parameters in the execute() method (pre-filtered, although there's FAR better filtering techniques) and return all results associated with your query.
Even if you decide not to use this, give it a thought at least... it's a good starting point on PDO and, of course, get a nice tutorial on GET/POST variable filtering (or use a 3rd-party tool like HTML Purifier, for that matter).
Hope that helps ;)
I'm terribly bad at keeping MySQL queries straight, but that aside I have one query working for some data input, but not all. My guess is quotation marks getting escaped where they should be.
I have the entire query string get escaped at the same time. Is this bad practice or does it really matter?
Here's the query:
"INSERT INTO bio_manager_pubs(userid,category,citation,date,link,requests) VALUES ( ".
$userid.",'".
$_POST['category']."', '".
htmlentities($_POST['pub'])."',
FROM_UNIXTIME(".strtotime($_POST['date'])."),'".
$_POST['link']."',
0)"
In query:
Userid and requests are ints
Link and Category are Tiny Text (not sure if that's appropriate, but max is 255 char, so would VarChar be better?)
Date is a date (is it better to reformat with php or reformat with mysql?)
Citation is a text field
Any ideas?
Thanks
EDIT:
The answer to this question was posted four times there abouts where the issue was me escaping the entire query.
What was left out, and cause some confusion was the code surrounding the query.
It was like this
$db->query($query)
This where the function query was:
public function query($SQL)
{
$this->SQL = $this->mysqli->real_escape_string($SQL);
$this->result = $this->mysqli->query($SQL);
if ($this->result == true)
{
return true;
}
else
{
printf("<b>Problem with SQL:</b> %s\n", $this->SQL);
exit;
}
}
I just found a class that made life a bit simpler on smaller projects and stuck with it. Now, the issue I'm running into is removing $this->mysqli->real_escape_string($SQL); and adding in escapes elsewhere in the code.
I really don't see any sanitizing of your $_POST data, and there is really no need to run htmlentities before you insert into the database, that should be done when you take that data and display it on the page. Make sure to sanitize your posts!! Using mysql_real_escape_string() or preferably PDO with prepared statements.
If you are running mysql_real_escape_string() on this whole query, after you build it, than that is what is breaking it.
Use it on the individual posts, and / or cast variables that should only ever be numbers to integers.
Heres what I would change it to in your case:
$posted = $_POST;
foreach($posted as &$value)
$value = mysql_real_escape_string($value);
$date = strtotime($posted['date']);
$q = "INSERT INTO bio_manager_pubs(userid,category,citation,date,link,requests) VALUES
(
'{$userid}',
'{$posted['category']}',
'{$posted['pub'])}',
FROM_UNIXTIME({$posted['date']}),
'{$posted['link']}',
'0'
)";
I believe it is considered bad practice to build the entire query and then escape the whole thing. You should sanitize the inputs as soon as they enter the code, not after you've started using them to build your database interactions.
You'd want to sanitize each input, kind of like this:
$category = mysql_real_escape_string($_POST['category'])
And then you'd use the local variables, not the inputs, to build your SQL command(s).
Also, you may want to look into something like PDO for your data access, which manages a lot of the details for you.
I think you need to wrap each of your inputs in mysql_real_escape_string (only once!), not the whole query. Other than that it looks OK to me.
"INSERT INTO bio_manager_pubs(userid,category,citation,date,link,requests) VALUES ( ".
mysql_real_escape_string($userid).",'".
mysql_real_escape_string($_POST['category'])."', '".
mysql_real_escape_string(htmlentities($_POST['pub']))."',
FROM_UNIXTIME(".mysql_real_escape_string(strtotime($_POST['date']))."),'".
mysql_real_escape_string($_POST['link'])."',
0)"
Instead of escaping the entire SQL query (which can run the risk of breaking things), just escape the user's input:
$userid = mysql_real_escape_string($userid);
$cat = mysql_real_escape_string($_POST['category']);
$pub = mysql_real_escape_string($_POST['pub']);
$date = strtotime($_POST['date']);
$link = mysql_real_escape_string($_POST['link']);
$query = "INSERT INTO bio_manager_pubs(userid, category, citation, date, link, requests)"
." VALUES ($userid, '$cat', '$pub', $date, '$link', 0 );";
Well for a start you should avoid using data from external sources directly in a query, so I would rewrite the code so as not to use $_POST in your query. Even better if you can to use PDO or similar to escape your data. And I would avoid converting text with htmlentities before inserting it into your database. You're better off doing that after you pull it from the database as you will then be able to use that data in other (non-HTML) output contexts.
But in terms of inline code, do you have magic_quotes on?
Try something like this
if (get_magic_quotes_gpc()) {
$category = stripslashes($_POST['category']);
$pub = stripslashes($_POST['pub']);
$link = stripslashes($_POST['link']);
} else {
$category = $_POST['category'];
$category = $_POST['category'];
$category = $_POST['category'];
}
$category = mysql_escape_string( $category );
$pub = mysql_escape_string( $pub );
$link = mysql_escape_string( $link );
$sql = "
INSERT INTO bio_manager_pubs(userid,category,citation,date,link,requests) VALUES (
". $userid.",
'$category',
'$pub',
FROM_UNIXTIME(".strtotime($_POST['date'])."),
'$link',
0
)";
Turn off magic_quotes_gpc and use prepared statements.
With magic_quotes_gpc disabled, you don't end up with automatic escaping of input - and magic_quotes_gpc is deprecated anyway.
Use parameter binding prepared statements to avoid SQL injection rather than escaping characters. I personally suggest using PDO or MDB2 to talk to your db, but you can also do prepared statements with the mysqli driver. Note that the mysql driver is on the chopping block as well, so you soon will be forced to either use mysqli or an abstraction layer like MDB2.
I bet though that magic_quotes_gpc is your problem.
Should be a simple question, I'm just not familiar with PHP syntax and I am wondering if the following code is safe from SQL injection attacks?:
private function _getAllIngredients($animal = null, $type = null) {
$ingredients = null;
if($animal != null && $type != null) {
$query = 'SELECT id, name, brief_description, description,
food_type, ingredient_type, image, price,
created_on, updated_on
FROM ingredient
WHERE food_type = \'' . $animal . '\'
AND ingredient_type =\'' . $type . '\';';
$rows = $this->query($query);
if(count($rows) > 0) {
etc, etc, etc
I've googled around a bit and it seems that injection safe code seems to look different than the WHERE food_type = \'' . $animal . '\' syntax used here.
Sorry, I don't know what version of PHP or MySQL that is being used here, or if any 3rd party libraries are being used, can anyone with expertise offer any input?
UPDATE
What purpose does the \ serve in the statement?:
WHERE food_type = \'' . $animal . '\'
In my googling, I came across many references to mysql_real_escape_string...is this a function to protect from SQL Injection and other nastiness?
The class declaration is:
class DCIngredient extends SSDataController
So is it conceivable that mysql_real_escape_string is included in there?
Should I be asking to see the implementation of SSDataController?
Yes this code is vulnerable to SQL-Injection.
The "\" escapse only the quote character, otherwise PHP thinks the quote will end your (sql-)string.
Also as you deliver the whole SQL-String to the SSDataControler Class, it is not possible anymore to avoid the attack, if a prepared string has been injected.
So the class SSDataControler is broken (vulnerable) by design.
try something more safe like this:
$db_connection = new mysqli("host", "user", "pass", "db");
$statement = $db_connection->prepare("SELECT id, name, brief_description, description,
food_type, ingredient_type, image, price,
created_on, updated_on
FROM ingredient
WHERE food_type = ?
AND ingredient_type = ?;';");
$statement->bind_param("s", $animal);
$statement->bind_param("s", $type);
$statement->execute();
by using the bind method, you can specify the type of your parameter(s for string, i for integer, etc) and you will never think about sql injection again
You might as well use mysql_real_escape_string anyway to get rid of anything that could do a drop table, or execute any other arbitrary code.
It doesn't matter where in the SQL statement you put the values, at any point it can have a ';' in it, which immediately ends the statement and starts a new one, which means the hacker can do almost anything he wants.
To be safe, just wrap your values in mysql_real_escape_string($variable). So:
WHERE Something='".mysql_real_escape_string($variable)."'
$animal can be a string which contains '; drop table blah; -- so yes, this is vunerable to SQL injection.
You should look into using prepared statements, where you bind parameters, so that injection cannot occur:
http://us3.php.net/pdo.prepared-statements
It is vulnerable. If I passed: '\'; DROP TABLE ingredient; SELECT \''
as $type, poof, goodbye ingredient table.
If its a private function, kind of. If you're concerned about people with access to the source injecting SQL, there are simpler ways to accomplish their goal. I recommend passing the arguments to mysql_real_escape_string() before use, just to be safe. Like this:
private function _getAllIngredients($animal = null, $type = null) {
$animal = mysql_real_escape_string($animal);
$type = mysql_real_escape_string($type);
...
}
To be extra safe, you might even pass it to htmlentities() with the ENT_QUOTES flag instead - that would also help safeguard against XSS type stuff, unless you're putting the contents of those DB entries into a <script> tag.
But the safest thing you can do is write your own sanitizing function, which would make the best of various techniques, and also allow you to easily protect against new threats which may arise in the future.
Re: UPDATE
The \'' serves to enclose the variable in quotes, so that when it goes through to SQL, nothing is broken by whitespace. IE: Where Something=Cold Turkey would end with an error, where Something='Cold Turkey' would not.
Furthermore, the class extension won't affect how you put together MySQL Statements.
If the the user or any 3rd party has anyway of injecting a value of $animal into your system (which they probably do), then yes it is vunerable to sql injection.
The way to get around this would be to do
private function _getAllIngredients($animal = null, $type = null) {
$ingredients = null;
if($animal != null && $type != null) {
$query = 'SELECT id, name, brief_description, description,
food_type, ingredient_type, image, price,
created_on, updated_on
FROM ingredient
$rows = $this->query($query);
if(count($rows) > 0) {
if($rows['animal'] == $animal && $rows['ingredient_type'] == $type) {
Note: I removed WHERE statements from sql and added if statements to loop