Protect from injections and right syntax for $_GET method - php

So, I am trying to use the get method while protecting from injections. I'm trying to get data from the database and echo it out to a page. I think it's pretty obvious what I'm trying to do with the code below but i need help with using the right syntax.
Can someone show me the right syntax for the prepare statement to get data from a database using mysqli that is protected from injections?
I've looked on this site can't seem to find what I'm looking for and the PHP site I couldn't find an up to date method. Thanks for all the help.
<?php
$mysqli = new mysqli("", "", "", "");
if ($mysqli->connect_error) {
echo "Failed to connect to MySQL: (" . $mysqli->connect_error . ") " . $mysqli->connect_error;
}
$stmt = $mysqli->stmt_init();
if($stmt->prepare("SELECT 'name,name' FROM 'table' WHERE 'name, name' = ?,?")) {
}
if (!$stmt->bind_param('si', $_GET['name'], $_GET['name'])); {
echo "Binding parameters failed: (" . $stmt->error . ") " . $stmt->error;
}
if (!$stmt->execute()) {
echo "Execute failed: (" . $stmt->error . ") " . $stmt->error;
}
if (!$stmt->fetch()); {
echo "Binding parameters failed: (" . $stmt->error . ") " . $stmt->error;
}
$stmt->close();
?>

your sql is wrong:
if($stmt->prepare("SELECT 'name,name' FROM 'table' WHERE 'name, name' = ?,?")) {
must be
if($stmt->prepare("SELECT name, name FROM table WHERE name=? AND name=? ")) {
Double the expressive name, I used only because of the question.
The following is clearer:
if($stmt->prepare("SELECT astring, ainteger FROM table WHERE astring=? AND ainteger=? "))
{
if (!$stmt->bind_param('si', $_GET['astring'], $_GET['ainteger'])) {
Take out some time to write the question carefully. If two variables are used, then designate different, everything else just confused.
Update :
Before you use bind_param()
You have to test all $_GET["xx"].
if (isset($_GET['name']))
When you call a function, terminated with ; for example:
if (!$stmt->bind_param('si', $_GET['name'], $_GET['name'])); {
Then the curly braces are useless, no matter the if gets true or false!
The following code after if (!$stmt->bind_param(...)); will always be executed, because the command, is finished.
if (!$stmt->bind_param('si', $_GET['name'], $_GET['name'])); {
echo "Binding parameters failed: (" . $stmt->error . ") " . $stmt->error;
}
It took a long time until I found this error. It is easily overlooked.
That's why you always get your own error messages.

to protect from sql injection, you should first make a connection to your mysql database and after that you should surround your $_GET with mysql_real_escape_string(), like this:
mysql_real_escape_string($_GET['name'])
or to use the newer function
mysqli_real_escape_string($_GET['name'])

This is better solution if you whant to protect all GET inputs:
function GET($name=NULL, $value=false)
{
$content=(!empty($_GET[$name]) ? trim($_GET[$name]) : (!empty($value) && !is_array($value) ? trim($value) : false));
if(is_numeric($content))
return preg_replace("#([^0-9])#Ui", "", $content);
else if(is_bool($content))
return ($content?true:false);
else if(is_float($content))
return preg_replace("#([^0-9\,\.\+\-])#Ui", "", $content);
else if(is_string($content))
{
if(filter_var ($content, FILTER_VALIDATE_URL))
return $content;
else if(filter_var ($content, FILTER_VALIDATE_EMAIL))
return $content;
else if(filter_var ($content, FILTER_VALIDATE_IP))
return $content;
else if(filter_var ($content, FILTER_VALIDATE_FLOAT))
return $content;
else
return preg_replace("#([^a-zA-Z0-9\+\-\_\*\#\$\!\;\.\?\#\:\=\%\/\ ]+)#Ui", "", $content);
}
else false;
}
Just instead $_GET['something'] you use GET('something') and you have option to put default value if GET value don't exists. And lather in MySQL query you can use escape string or prepared state to full protect your query.

Related

How can I check for duplicate usernames using PHP and MySQL?

I'm just learning PHP and I thought it would be a good idea to learn some MySQL too.So I started working on the code and for some strange reason I keep getting duplicate users which is really really bad.
<?php
$link = mysqli_connect(here i put the data);
if(!$link)
{
echo "Error: " . mysqli_connect_errno() . PHP_EOL;
exit;
}
else
{
if(isset($_POST['user']))
{ echo "User set! "; }
else { echo "User not set!"; exit; }
if(isset($_POST['pass']) && !empty($_POST['pass']))
{ echo "Password set! "; }
else { echo "Password not set!"; exit; }
$num = mysqli_num_rows(mysqli_query("SELECT * FROM `users` WHERE ( username = "."'".$_POST['user']."' )"));
if($num > 0)
{ echo "Cannot add duplicate user!"; }
mysqli_close($link);
}
?>
For some strange reason I don't get the output I should get.I've tried some solutions found here on StackOverflow but they didn't work.
The first parameter of connectionObject is not given in mysqli_query:
$num = mysqli_num_rows(mysqli_query($link, "SELECT * FROM `users` WHERE ( `username` = '".$_POST['user']."' )"));
//----------------------------------^^^^^^^
Also, your code is vulnerable to SQL Injection. A simple fix would be:
$_POST['user'] = mysqli_real_escape_string($link, $_POST['user']);
mysqli_query must receive two parameters in order to work. In this case, your mysqli_connect.
$num = mysqli_num_rows(mysqli_query($link, "SELECT * FROM `users` WHERE ( username = "."'".$_POST['user']."' )"));
Also, you can be affected by SQL Injection, in this code.
Never add user input directly in your queries without filtering them.
Do that to make your query more readable and safe:
$u_name=mysqli_real_escape_string($link, $_POST['user']);
$num = mysqli_num_rows(mysqli_query($link, "SELECT * FROM `users` WHERE ( username = '$u_name' )"));
To use mysqli_* extension, you must include your connection inside of the parameters of all queries.
$query = mysqli_query($link, ...); // notice using the "link" variable before calling the query
$num = mysqli_num_rows($query);
Alternatively, what you could do is create a query() function within your website, like so:
$link = mysqli_connect(...);
function query($sql){
return mysqli_query($link, $sql);
}
and then call it like so:
query("SELECT * FROM...");
This could be a problem of race condition.
Imagine that two users wants to create the same username at the same time.
Two processes will execute your script. So both scripts select from database and find out that there is not an user with required username. Then, both insert the username.
Best solution is to create unique index on username column in the database.
ALTER TABLE users ADD unique index username_uix (username);
Then try insert the user and if it fails, you know the username exists ...
Here's how to write your code using prepared statements and error checking.
Also uses a SELECT COUNT(*)... to find the number of users instead of relying on mysqli_num_rows. That'll return less data from the database and just seems cleaner imo.
<?php
$link = mysqli_connect(here i put the data);
if(!$link) {
echo "Error: " . mysqli_connect_errno() . PHP_EOL;
exit;
}
else if(!isset($_POST['user'])) {
echo "User not set!"; exit;
}
echo "User set! ";
if(!isset($_POST['pass']) || empty($_POST['pass'])) {
echo "Password not set!"; exit;
}
echo "Password set! ";
$query = "SELECT COUNT(username)
FROM users
WHERE username = ?";
if (!($stmt = $mysqli->prepare($query))) {
echo "Prepare failed: (" . mysqli_errno($link) . ") " . mysqli_error($link);
mysqli_close($link);
exit;
}
$user = $_POST ['user'];
$pass = $_POST ['pass'];
if(!mysqli_stmt_bind_param($stmt, 's', $user)) {
echo "Execute failed: (" . mysqli_stmt_errno($stmt) . ") " . mysqli_stmt_error($stmt);
mysqli_stmt_close($stmt);
mysqli_close($link);
exit;
}
if (!mysqli_execute($stmt)) {
echo "Execute failed: (" . mysqli_stmt_errno($stmt) . ") " . mysqli_stmt_error($stmt);
mysqli_stmt_close($stmt);
mysqli_close($link);
exit;
}
$result = mysqli_stmt_get_result($stmt);
if ($row = mysqli_fetch_array($result, MYSQLI_NUM)) {
$num = $row[0];
if($num > 0) {
echo "Cannot add duplicate user!";
}
}
mysqli_stmt_close($stmt);
mysqli_close($link);
please do suggest fixes to syntax, this was typed from a phone

MYSQL assign column name to variable?

I have a database table which has two columns, business and tourist.
I ask a user to select one of them from dropdown list, then use the result in a SELECT statement in MySQL. I assign this column to $cclass, then I make this statement SELECT $cclass FROM flights ....
But it always returns NULL. Why does it return NULL and how do I fix this?
My code:
$check = mysql_query("SELECT $cclass FROM flights WHERE flight_no = '$flightno'");
while ($result = mysql_fetch_assoc($check))
{
$db_seats = $result['$cclass'];
}
you should replace this line:
$db_seats = $result['$cclass'];
with this:
$db_seats = $result[$cclass];
string between 2 single quotes doesn't parsed:
Strings
Have you tried doing the following:
$check = mysql_query("SELECT".$cclass." FROM flights WHERE flight_no = '$flightno'");
First of all, this code has a serious security issue, as it is vulnerable to SQL Injection. You should be using the MySQLi extension instead, and properly filtering your input.
Try something like this:
<?php
/* Create the connection. */
$mysql = new mysqli("localhost", "username", "password", "myDB");
if ($mysql->connect_error)
{
error_log("Connection failed: " . $mysql->connect_error);
die("Connection failed: " . $mysql->connect_error);
}
/* Sanitize user input. */
if (!in_array($cclass, array('business', 'tourist')))
{
error_log("Invalid input: Must be 'business' or 'tourist'");
die("Invalid input: Must be 'business' or 'tourist'");
}
$statement = $mysql->stmt_init();
$statement->prepare("SELECT $cclass FROM flights WHERE flight_no = ?");
$statement->bind_param("s", $flightno);
if (!$statement->execute())
{
error_log("Query failed: " . $statement->error);
die("Query failed: " . $statement->error);
}
if ($statement->num_rows < 1)
{
echo "No results found.";
}
else
{
$statement->bind_result($seats);
while ($statement->fetch())
{
echo "Result: $seats";
// Continue to process the data... You can just use $seats.
}
}
$mysql->close();
However, the reason your original example is failing, is that you're quoting $cclass:
$db_seats = $result[$cclass];
However, please do not ignore the serious security risks noted above.

How I can check error in my mysqli? [duplicate]

This question already has an answer here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(1 answer)
Closed 2 years ago.
I have a code below... and sometimes this code just give me information that everything is ok, and "success" msg. But new row from insert is not added to database.
I thought: echo $this->mysqli->error; will give me error but it's not working?
if ($stmt = $this->mysqli->prepare("INSERT INTO tournaments ("
. "id_system, "
. "id_rank_admin, "
. "id_tournament_class, "
. "id_season, "
. "tournament_name,"
. "description,"
. "city,"
. "address,"
. "tournament_date,"
. "start_time,"
. "entry_fee,"
. "tournament_type,"
. "accepted_expansions,"
. "prices,"
. "additional_info,"
. "status,"
. "organizer_name,"
. "organizer_logo,"
. "organizer_link) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "))
{
$stmt->bind_param("sssssssssssssssssss",
$this->id_system,
$this->id_rank_admin,
$this->it_tournament_class,
$this->id_season,
$this->tournament_name,
$this->description,
$this->city,
$this->address,
$this->tournament_date,
$this->start_time,
$this->entry_fee,
$this->tournament_type,
$this->accepted_expansions,
$this->prices,
$this->additional_info,
$this->status,
$this->organizer_name,
$this->organizer_logo,
$this->organizer_link);
$stmt->execute();
$stmt->close();
}
else
{
echo $this->mysqli->error;
}
$ok=$stmt->execute();
if($ok)
{
echo "Query Executed Successfully";
}
else
{
echo(mysqli_error($link));
}
The mysqli->execute what it does is returns true or false based on it you can get your error i'm not in to too much of mysqli oop way so if any syntax is wrong correct it
I found this here: http://php.net/manual/en/mysqli.error.php
string mysqli_error ( mysqli $link )
Returns the last error message for the most recent MySQLi function call that can succeed or fail.
Might give you a better understanding of where the error is.
Try this:
$link = mysqli_connect("localhost", "my_user", "my_password", "db");
else
{
echo(mysqli_error($link));
}

Cannot pass parameter when attempting prepared statement

I'm attempting to learn prepared statements right now in PHP/MYSQL because of many suggestions around here. I keep getting this error:
Fatal error: Cannot pass parameter 2 by reference in C:\xampp\htdocs\blog\admin\create.php on line 57
Can anyone tell me how to fix this problem? I've been searching around and I can't find anything that will help me solve this.
Here is my code:
<?php
require_once '../config.php';
// Check to see if the title was entered from new.php
if ($_POST['title'])
{
$title = $_POST['title'];
} else {
echo "No title was entered. Please go back. <br />";
}
// Check to see if the body was entered from new.php
if ($_POST['body'])
{
$body = $_POST['body'];
} else {
echo "No body was entered. Please go back. <br />";
}
// Get the date
$date = time();
// ID = NULL because of auto-increment
$id = 'NULL';
// If magic_quotes_gpc returns true then it's enabled on the serever and all variables will be
// automatically escaped with slashes. If it isn't true then it's done manually
if (!get_magic_quotes_gpc())
{
$title = addslashes($title);
$body = addslashes($body);
$date = addslashes($date);
}
// Connect to the database
$db = new mysqli('localhost','username','password','database');
// Check to see if the connection works
if ($db->connect_errno)
{
echo 'Error: Could not connect to database. Please try again.';
exit;
}
// Prepared statement for a query to place something in the database
if(!($stmt = $db->prepare("insert into pages (id, title, body, date) values (?,?,?,?)")))
{
echo "Prepare failed: (" .$db->errno . ")" . $db->error;
}
// THIS IS THE LINE WHERE I'M RECEIVING THE ERROR!!!!!!!!
if (!$stmt->bind_param('isss', ''.$id.'', ''.$title.'',''.$body.'',''.$date.''))
{
echo "Binding parameters failed: (" .$stmt->errno. ")" . $stmt->error;
}
if (!$stmt->execute())
{
echo "Execute failed: (" .$stmt->errno . ") " .$stmt->error;
}
$db->close;
?>
You should have a look at the corresponding mysqli_stmt::bind_param documentation. More precisely, have a look at the function's definition:
bool mysqli_stmt::bind_param ( string $types , mixed &$var1 [, mixed &$... ] )
Notice the mixed &$var1 part? This basically states that your paramters are passed by reference and not by value (which would look like mixed $var1 - the & makes the difference).
Now, the problem with your invocation is that you are trying to pass an expression rather than a variable by reference. From the PHP documentation:
The following things can be passed by reference:
- Variables, i.e. foo($a)
- New statements, i.e. foo(new foobar())
- References returned from functions, [...]
The simple remedy is to first call the binding with uninitialized variables which are then assigned your processed input data, i.e.
// Prepared statement for a query to place something in the database
$stmt = $db->prepare("insert into pages (id, title, body, date) values (?,?,?,?)");
if ( !$stmt ) {
echo "Prepare failed: (" .$db->errno . ")" . $db->error;
}
if ( !$stmt->bind_param('isss', $stmt_id, $stmt_title, $stmt_body, $stmt_date) ) {
echo "Binding parameters failed: (" .$stmt->errno. ")" . $stmt->error;
}
$stmt_id = (int) $id;
$stmt_title = (string) $title;
$stmt_body = (string) $body;
$stmt_date = (string) $date;
if ( !$stmt->execute() ) {
echo "Execute failed: (" .$stmt->errno . ") " .$stmt->error;
}

PHP/MYSQLI - How to check if this query is possible, if so show error (see example)

I am learning some myqli and would like to make a simple check.
Basically, A user will enter their email addess then submit a form, if the email address is already contained in a certain mysql table, then the script must stop with an error.
This is my example:
$userEmail = sanitize($_POST['specials']);
// Check to see if email already exists, if not proceed
if ($stmt = $link->prepare("SELECT email FROM specials WHERE email=$userEmail"))
{
$specialsErrorFocus = 'autofocus="autofocus"';
$specialsInfo = 'This email address: $userEmail, is already in our database.';
include "$docRoot/html/shop/home.html.php";
exit();
}
This code does not do as I have intended it to as described.
Could someone please explain where I am going wrong with this, or possibly offer a better solution for this task.
Thanks in advance!
You need to execute the query first, as simply preparing the statement is not sufficient. See the documentation as it is a multi stage process.
First, you prepare the statement:
$stmt = $link->prepare("SELECT `email` FROM `specials` WHERE `email` = ?")
if (!$stmt) {
echo $link->errno . " : " . $link->error;
}
Next, bind the parameters:
if (!$stmt->bind_param("s", $userEmail)) {
echo $stmt->errno . " : " . $stmt->error;
}
Finally, execute the query:
if (!$stmt->execute()) {
echo $stmt->errno . " : " . $stmt->error;
}
Get the results:
$stmt->store_result();
if ($stmt->num_rows) {
# Email exists
}
Prepare does not execute the statement. You can use mysql::query to execute the statement.
Your Example would become:
$result = $link->query("SELECT email FROM specials WHERE email=$userEmail");
if ( $result ) {
if ( $result->num_rows > 0 ) {
$specialsErrorFocus = 'autofocus="autofocus"';
$specialsInfo = 'This email address: $userEmail, is already in our database.';
include "$docRoot/html/shop/home.html.php";
exit();
}
}

Categories