I have a large sql query which I am trying to prevent injection on.
Because the query uses like and '%' on the variables I do not know how to format it and my usual method of
$sql = "INSERT into UsedBook ( userId, bookId, price, description ) VALUES
(?,?,?,?)";
if($stmt = mysqli_prepare($conn, $sql)){
mysqli_stmt_bind_param($stmt, "iiis", $userId, $bookId, $price,
$description);
mysqli_stmt_execute($stmt);
}
Doesn't fit the format.
Here is my large query. Look near the bottom for the like statements with the variables.
$sql = "SELECT DISTINCT Offering.offeringId, UsedBook.saleId,
UsedBook.bookId, UsedBook.price,
UsedBook.timeStamp, Book.bookName, Classes.classNumber, Instructor.name,
Classes.departmentName, Offering.section, Users.email, UsedBook.description
FROM UsedBook, Book, Classes, Offering, Instructor, RequiredBook, Users
WHERE UsedBook.bookId = Book.bookId
and Classes.classId = RequiredBook.classId and Book.bookId =
RequiredBook.bookId
and Classes.classId = Offering.classId and Offering.instructorId =
Instructor.instructorId
and Offering.semesterId = $semester and UsedBook.userId = Users.userId and
UsedBook.userId != $userId
and Classes.departmentName like '$departmentName%' and Classes.classNumber
like '$classNumber%'
and Book.bookName like '$bookName%' and Offering.section like '$section%'";
You can still use a prepared statement, you just need to incorporate the % into the bound parameter e.g.
$sql = "SELECT * FROM UsedBook WHERE bookName LIKE ?";
$param = "$bookName%";
if($stmt = mysqli_prepare($conn, $sql)){
mysqli_stmt_bind_param($stmt, "s", $param);
mysqli_stmt_execute($stmt);
}
Related
The data on the form failed to saved on the database. I cannot find what's wrong here. I already checked the name of the input forms an it is all correct. I'm using PDO
if ($_POST) {
$accountuname = ($_POST['accountuname']);
$accountpassword = ($_POST['accountpassword']);
$accounttype = ($_POST['accounttype']);
$companyname = ($_POST['companyname']);
$companyproduct = ($_POST['companyproduct']);
$companyaddress = ($_POST['companyaddress']);
$companycontactnum = ($_POST['companycontactnum']);
$query = "INSERT INTO user_accounts SET USER_NAME=?, USER_PASS=?, USER_ACC_TYPE=?, COMPANY_NAME=?, COMPANY_PRODUCT=?, COMPANY_ADDRESS=?, COMPANY_CONTACTNUM=?";
$stmt = $conn->prepare($query);
$stmt -> bindParam(1,$accountuname);
$stmt -> bindParam(2,$accountpassword);
$stmt -> bindParam(3,$accounttype);
$stmt -> bindParam(4,$companyname);
$stmt -> bindParam(5,$companyproduct);
$stmt -> bindParam(6,$companyaddress);
$stmt -> bindParam(7,$companycontactnum);
$stmt -> execute();
}else{
header("location:index.php");
}
Change the SQL query from:
INSERT INTO user_accounts SET USER_NAME=?, USER_PASS=?, USER_ACC_TYPE=?, COMPANY_NAME=?, COMPANY_PRODUCT=?, COMPANY_ADDRESS=?, COMPANY_CONTACTNUM=?
To:
INSERT INTO user_accounts (USER_NAME, USER_PASS, USER_ACC_TYPE, COMPANY_NAME, COMPANY_PRODUCT, COMPANY_ADDRESS, COMPANY_CONTACTNUM) VALUES (?, ?, ?, ?, ?, ?, ?)
INSERT INTO syntax.
If you are using mysqli, acording to the documentation, the bind_param (instead of bindParam... maybe you are using a framework?) function expects the first parameter to be a string, instead of an int:
bind_param ( string $types , mixed &$var1 [, mixed &$... ] )
types
A string that contains one or more characters which specify the types
for the corresponding bind variables:
i corresponding variable has type integer
d corresponding variable has type double
s corresponding variable has type string
b corresponding variable is a blob and will be sent in packets
You should change the 1,2,3,4... to 'd,s,b' (the variable type), and it should work.
Hope it helps!
You have to specify the binded parameter type, and also your query was incorrect.
Here is the correct version in MySQLi:
$query = "INSERT INTO user_accounts (USER_NAME, USER_PASS, USER_ACC_TYPE, COMPANY_NAME, COMPANY_PRODUCT, COMPANY_ADDRESS, COMPANY_CONTACTNUM) VALUES (?, ?, ?, ?, ?, ?, ?)";
$stmt = $conn->prepare($query);
$stmt->bindParam("sssssss", $accountuname, $accountpassword, $accounttype, $companyname, $companyproduct, $companyaddress, $companycontactnum);
// Set parameters and execute
$accountuname = $_POST['accountuname'];
$accountpassword = $_POST['accountpassword'];
$accounttype = $_POST['accounttype'];
$companyname = $_POST['companyname'];
$companyproduct = $_POST['companyproduct'];
$companyaddress = $_POST['companyaddress'];
$companycontactnum = $_POST['companycontactnum'];
$stmt->execute();
Here is the correct version in PDO:
$query = "INSERT INTO user_accounts (USER_NAME, USER_PASS, USER_ACC_TYPE, COMPANY_NAME, COMPANY_PRODUCT, COMPANY_ADDRESS, COMPANY_CONTACTNUM) VALUES (:uname, :upass, :utype, :cname, :cproduct, :caddress, :ccontactnum)";
$stmt = $conn->prepare($query);
$stmt->bindParam(':uname', $accountuname);
$stmt->bindParam(':upass', $accountpassword);
$stmt->bindParam(':utype', $accounttype);
$stmt->bindParam(':cname', $companyname);
$stmt->bindParam(':cproduct', $companyproduct);
$stmt->bindParam(':caddress', $companyaddress);
$stmt->bindParam(':ccontactnum', $companycontactnum);
// Set parameters and execute
$accountuname = $_POST['accountuname'];
$accountpassword = $_POST['accountpassword'];
$accounttype = $_POST['accounttype'];
$companyname = $_POST['companyname'];
$companyproduct = $_POST['companyproduct'];
$companyaddress = $_POST['companyaddress'];
$companycontactnum = $_POST['companycontactnum'];
$stmt->execute();
For MYSQLi: In this example I assumed all the posted data are string, otherwise you would have to change the 'sssssss' in the bindParam function.
Read more about prepared statements here
Read more about MySQLi INSERT syntax here
Is it possible to have a "mixed" SQL Insert like the following?
I want to be able to get one value from another table (that needs a param) and then enter in 2 more params.
$sql = "INSERT INTO tblquestions (userID, questionText, questionAnswer) VALUES (
Select userID FROM tblusers WHERE userEmail = (?),?,?)";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 'sss', $userEmail, $question, $answer);
$result = mysqli_stmt_execute($stmt);
if (!$result) {
throw new Exception($conn->error);
}
It is unnecessary. Just use insert . . . select:
INSERT INTO tblquestions(userID, questionText, questionAnswer)
Select userID, ?, ?
FROM tblusers
WHERE userEmail = (?);
I'm trying to replace every "?" in string by values from array. Each "?" is the next value from array.
I was wondering if there is a better way to do the following:
$query = 'SELECT * FROM pages WHERE id = ? AND language = ?';
$values = array('1', 'en');
foreach ($values as $value) {
$query = preg_replace('/\?/', '\''.$value.'\'', $query, 1);
}
echo '<pre>'.print_r($query, true).'</pre>';
Would like to do that with native PHP (not a PDO extension).
Use binding
in PDO
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->bindValue(':calories', $calories, PDO::PARAM_INT);
$sth->bindValue(':colour', $colour, PDO::PARAM_STR);
$sth->execute();
http://php.net/manual/pl/pdostatement.bindvalue.php
in mysqli
$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$stmt->bind_param('sssd', $code, $language, $official, $percent);
http://www.php.net/manual/en/mysqli-stmt.bind-param.php
if you want to do it in STUPID way you can use loop or recursion
$select = "SELECT * FROM pages WHERE id = ? AND language = ?";
$params = array('param', 'param2');
while(preg_match('/\?/', $select)) $select = str_replace("?", array_shift($params), $select);
but it's stupid
Mysqli and PDO are as native as it gets with PHP.
You can use bind_param from mysqli to accomplish this. Example:
$stmt = $mysqli->prepare("SELECT * FROM pages WHERE id = ? AND language = ?");
$stmt->bind_param('is', 1, "en");
In this case the i and s are referencing the type of the parameter, as seen in this table (available in link):
i corresponding variable has type integer
d corresponding variable has type double
s corresponding variable has type string
b corresponding variable is a blob and will be sent in packets
Hey, I have a quick one. Is there any way to include a variable into a prepared query? example:
$sql = "SELECT id, title, author, LEFT(description, 40) AS excerpt,
image_small, image_med, date
FROM posts
ORDER BY id DESC
LIMIT $start, $postsPerPage";
$result = $connect->prepare($sql) or die ('error');
$result->execute();
$result->bind_result($id, $title, $author, $excerpt, $image_small, $image_med, $date);
Thanks!
you want the following:
$start = 1; $postsPerPage = 1;
$sql = "SELECT id, title, author, LEFT(description, 40) AS excerpt,
image_small, image_med, date
FROM posts
ORDER BY id DESC
LIMIT ?, ?";
$stmt = $connect->prepare($sql) or die ('error');
$stmt->bind_param('ii', $start, $postsPerPage);
$stmt->execute();
$stmt->bind_result($id, $title, $author, $excerpt, $image_small, $image_med, $date);
while($stmt->fetch()) {
printf('<h1>%s</h1><p>%s <small> by %s on %s</small></p>',
htmlspecialchars($title),
htmlspecialchars($excerpt),
htmlspecialchars($author),
htmlspecialchars($date)
);
}
this binds both question marks to integer (i) values of $start and $postsPerPage. do NOT use variables directly in prepared statements, because that would defeat the whole purpose of prepared statements (apart from eliminating parsing time)
Use question marks as placeholders in the SQL where you want the value of the variable to be.
Use mysqli_stmt::bind_param to bind values to the placeholders.
If I'm not mistaken you have to use bindParam and replace the variables in your query with a question mark
$sql = "SELECT id, title, author, LEFT(description, 40) AS excerpt,
image_small, image_med, date
FROM posts
ORDER BY id DESC
LIMIT ?, ?";
$result = $connect->prepare($sql) or die ('error');
$result->bindParam(1, $start);
$result->bindParam(2, $postsPerPage);
you can find more examples at http://php.net/manual/en/pdo.prepared-statements.php
I am trying to execute the following sql from php using pdo: SELECT * FROM my_table WHERE name=?.
When I do this:
$sql = 'SELECT * FROM my__table WHERE name=?' ;
$stmt = $dbconn->prepare($sql);
$stmt->bindValue(1, $_POST['name'], PDO::PARAM_STR);
$stmt->execute();
I get an empty result set.
When I do this:
$sql = 'SELECT * FROM my__table WHERE name=\''.$_POST['name'].'\'' ;
$stmt = $dbconn->prepare($sql);
$stmt->execute();
I get the row that I need.
The column 'name' is a VARCHAR(32). This bug only happens with strings. When the bound parameter is an sql INTEGER everything works like it is supposed to.
I am using sqlite3, php 5.2.6 under Apache on Ubuntu.
Both of these should work:
Without using binding
$sql = "SELECT * FROM my__table WHERE name = ? " ;
$stmt = $dbconn->prepare($sql);
$stmt->execute(array($_POST['name']));
Using a named parameter
$sql = "SELECT * FROM my__table WHERE name = :name " ;
$stmt = $dbconn->prepare($sql);
$stmt->bindParam(':name', $_POST['name'], PDO::PARAM_STR);
$stmt->execute(array($_POST['name']));
What about this?
$sql = "SELECT * FROM my__table WHERE name='?'" ;
$stmt = $dbconn->prepare($sql);
$stmt->bindValue(1, $_POST['name'], PDO::PARAM_STR);
$stmt->execute();