I was wondering if it's possible to prepare statements using PHP's pgsql library that do not require parameters.
I'm really used to preparing all my SQL statements in the beginning of a program instead of when I need them so my code always looks similar to this
<?php
$pgsqlCon = // code to connect
// prepare SQL statements
$sql = "SELECT * FROM table01 " .
"WHERE t01_idno >= $1";
pg_prepare($pgsqlCon, "table01_cur", $sql);
$sql = "SELECT * FROM table02 " .
"WHERE t02_idno = $1";
pg_prepare($pgsqlCon, "table02_sel", $sql);
// start main
$table01 = pg_execute($pgsqlCon, "table01_cur", array('1'));
while ($row = pg_fetch_row($table01)) {
echo "<span>found something<br /></span>";
}
$table02 = pg_execute($pgsqlCon, "table02_sel", array('1'));
while ($row = pg_fetch_row($table02)) {
echo "<span>found something else<br /></span>";
}
?>
So I would like to prepare statements that don't require parameters in this way as well if that is possible.
I had the same problem and sadly this usage is not documented in the official documentation.
Looking at it you can see that the third argument is not optional (i.e. not in brackets [..]) and indeed, as the above comment says, passing an empty array() as the third argument works.
So after preparing a statement with no arguments one could execute it like so:
$rs = pg_execute($connection, $stmt, array());
Related
I am some confused because some people write PHP code like this for upload data.
But my instructor used $query and $link always to upload and retrieve data from SQL.
<?php
include 'connection.php';
function reg_in() {
if (isset($_POST['submit'])) {
$name = $_POST['name'];
$email = $_POST['email'];
$mob = $_POST['mobile'];
$check_in = $_POST['in'];
$check_out = $_POST['out'];
$rm = $_POST['room'];
$room_type = $_POST['type'];
// Problem start from here
if (mysql_query("INSERT INTO `book` (`name`,`email`,`mobile_no`,`check_in`,`check_out`,`room`,`room_type`) VALUES ('$name','$email','$mob','$check_in','$check_out','$rm','$room_type')")) {
header('Location: C:/wamp/www/project/payment.html');
} else {
echo mysql_error();
}
}
}
if (isset($_POST['submit'])) {
reg_in();
//echo ' succesfully inserted';
} else {
echo 'Not book';
}
MySQL (by my instructor):-
<?php
$link = mysqli_connect("myserver.com", "test", "sunil7117", "test");
if (mysqli_connect_error()) {
die("please give correct permision");
}
//Is both are same!
//$query="INSERT INTO user(email,password) VALUES ('shivanandcpr25#gmail.com','sunil7117')";
$query = "UPDATE user SET email='test#gmail.com' WHERE email='abc#gmail.com' LIMIT 1";
echo mysqli_query($link, $query);
echo "<br>";
$query = "SELECT * FROM user";
if ($result = mysqli_query($link, $query)) {
echo "welcome to database<br>";
$row = mysqli_fetch_array($result);
echo "my E-mail id is <strong> ".$row[1]. "</strong> and passoword is <strong>".$row[2]."</strong>";
}
Neither!
Your first example uses function which has been removed from PHP years ago. mysql_query() does not exist and should not be used anymore. The reason why it was removed is that you should use prepared statements instead. They are provided by either mysqli or PDO extensions.
Your second example is better, but it is way too messy.
You should not echo mysqli_query. There's nothing useful to be printed out from this function.
Get into a habit of using prepared statements all the time and use placeholders for variable data. As of now your queries are constant, but using prepared statements is still a good practice in case you need to add a parameter later on.
Avoid using functions like mysqli_fetch_array(). Iterating the result option one by one is messy and rarely useful.
Never check the return value of mysqli calls. It's pointless. Enable error reporting instead. See How to get the error message in MySQLi?
Always set the correct charset. It should be utf8mb4 99% of the time.
The SQL query can be saved in a separate variable, but what's the point? You are only going to pass it as an argument to the query function. There's no need to use an intermediate variable.
Don't use mysqli. You should use PDO instead. If you have to use mysqli, then create a simple wrapper function or class for this purpose and execute your generic function instead of messing around with mysqli functions.
Here is an example of how I would do it. First I enable error reporting for mysqli, I open the connection and set the charset. Then I declare a function which takes 3 parameters and returns an array. First parameter is your database connection you have just opened. Second is your SQL query with placeholders if there are any. Third is optional and it is an array of values to be bound to the placeholders as parameters. This function works for all kind of SQL queries. The rest of the code becomes really simple.
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = new mysqli("myserver.com", "test", "sunil7117", "test");
$link->set_charset('utf8mb4'); // always set the charset
/**
* Executes an SQL query on the database.
*
* #param \mysqli $mysqli
* #param string $query e.g. SELECT * FROM users WHERE username=?
* #param array $params An array of parameters to be bound in the given order to the placeholders in SQL
* #return array
*/
function prepared_query(\mysqli $mysqli, string $query, array $params = []): array {
$stmt = $mysqli->prepare($query);
if ($params) {
$stmt->bind_param(str_repeat("s", count($params)), ...$params);
}
$stmt->execute();
if ($result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_BOTH);
}
return null;
}
prepared_query($link, "UPDATE user SET email='test#gmail.com' WHERE email='abc#gmail.com' LIMIT 1");
echo "<br>";
$result = prepared_query($link, "SELECT * FROM user");
echo "welcome to database<br>";
if ($result) {
$row = $result[0];
echo "my E-mail id is <strong> ".$row[1]. "</strong> and passoword is <strong>".$row[2]."</strong>";
}
I am very new to the whole PHP/MSSQL coding and need assistance with SQL Injection prevention.
I am adding a simple search feature to a website that uses a MSSQL database.
The code works as I want it to but it is vulnerable to SQL Injection.
Any other way to secure it except for prepare statements?
I am also not that familiar with stored procedures.
I have tried prepare statements with no luck(unless I'm doing something wrong, that's most likely)
Stored procedures I'm not familiar with.
<?PHP
$tech = (isset($_POST['Technician'])? $_POST['Technician'] : null);
$sql = "SELECT * FROM Errors WHERE Error LIKE '%$tech%' or Description LIKE '%$tech%'";
$name = trim($_POST['Technician']);
if(empty($name)){
print '<script type="text/javascript">alert("Please enter an Error Code or Error Description")</script>';
exit;
}
$stmt = sqlsrv_query($conn, $sql);
if ($stmt) {
$rows = sqlsrv_has_rows( $stmt );
if ($rows === true) {
echo "";
} else{
echo '<script type="text/javascript">alert("Please enter a valid Term")</script>';
}
}
while($db_field = sqlsrv_fetch_array($stmt)){
print '<table align="center" style="position: relative; width:250px; text-align: center;">';
print '<tr>';
print '<td>'.$db_field['Error']."</td></tr>";
print "<tr>";
print '<td>'.$db_field['Description'].'</td></tr>';
//print "<tr><th>"."Cause"."</th>";
//print "<td>".$db_field['Cause']."</td></tr>";
//print "<tr><th>"."Resolution"."</th>";
//print "<td>".$db_field['Resolution']."</td></tr>";
print "</table><br>";
}
sqlsrv_close($conn);
?>
I expect SQL Injection to fail when attempted.
Pretty simple to use a parameterized query, notice only ?:
$sql = "SELECT * FROM Errors WHERE Error LIKE ? OR Description LIKE ?";
Then build an array of parameters adding the LIKE wildcards %:
$params = array("%$tech%", "%$tech%");
Execute with parameters:
$stmt = sqlsrv_query( $conn, $sql, $params);
Alternatively, for flexibility with other queries, for the parameters you could do:
$tech = "%$tech%";
$params = array($tech, $tech);
Prepared statements are the simplest way to inject raw input into SQL. You can skip them altogether if you want but it comes at the price of greater complexity and lower security (and you need to write the alternative code yourself). The only reason why you can find escape() functions in other extensions (or no mechanism at all!) is because they're legacy libraries, sometimes very old ones. SQLSRV is reasonably modern.
Additionally, you may want to:
User filter functions to simply input checks.
Escape wildcard characters.
Resulting code would look like this:
$tech = filter_input(INPUT_POST, 'Technician');
if ($tech !== null) {
$sql = "SELECT *
FROM Errors
WHERE Error LIKE ? or Description LIKE ?";
$find = '%' . escapeLike($tech) . '%';
$params = [$find, $find];
$res = sqlsrv_query($conn, $sql, $params);
}
function escapeLike($value)
{
return strtr($value, [
'%' => '[%]',
'_' => '[_]',
'[' => '[[]',
]);
}
I'm having trouble updating a site. With security in mind, I am trying to rewrite the SQL statements using PDO prepared. It's my preferred choice generally.
The site I'm working on has this query, returning results via json to a search box. It works ...
$sql = "SELECT * FROM stock_c_ranges WHERE deleted = 'no' AND current_status = 'current'";
$result = mysqli_query($conn, $sql);
$results_list = array();
while($row = mysqli_fetch_array($result)){
$results_list[] = $row['manufacturer_name'].' ID:'.$row['id'];
}
echo json_encode($results_list);
I've re-written using prepared statements ...
$range = "SELECT * FROM stock_c_ranges WHERE deleted= :deleted AND current_status= :cstatus";
$deleted='no';
$c_status='current';
$result_lists=array();
$stmt=$pd_con->prepare($range);
$stmt->bindParam(':deleted',$deleted,PDO::PARAM_STR);
$stmt->bindParam(':cstatus',$c_status,PDO::PARAM_STR);
$stmt->execute;
while($row=$stmt->fetch(PDO::FETCH_ASSOC)){
$results_list[] = $row['manufacturer_name']. 'ID:'.$row['id'];
}
echo json_encode($results_list);
..... this doesn't
I've either made a glaring syntax error that I'm just blind to after looking at it for so long, or there is something about using PDO and JSON/AJAX that I'm not aware of stopping it functioning.
Apologies, writing it on here has highlighted the glaringly obvious ...
$stmt->execute;
Should have been ...
$stmt->execute();
I have a piece of code that reads a crash log and other metadata from a MySQL database before sending it back to the requester as JSON (this code is called by an AJAX function on another page). Optionally, filters can be specified with GET, which alter the prepared statement to filter for only the specified results - for example, to only show results from one app version. Here is the code in question:
$conn = new mysqli($sql_servername, $sql_username, $sql_password, "Crashes");
if ($conn->connect_error) {
//failed
die();
}
$sql="
SELECT ID,phone,appver,osver,user_agent,username,message,app_name,date_received FROM Crashes WHERE ";
$params="";
$params2="";
if (isset($_GET["filter_phone"])) {
$sql .= "phone = ? AND "; //i.e "WHERE phone = ? AND (...osver = ? AND appver = ? etc)"
$params.="s";
$params2.=', $_GET["filter_phone"]';
}
if (isset($_GET["filter_appver"])) {
$sql .= "appver = ? AND ";
$params.="s";
$params2.=', $_GET["filter_appver"]';
}
if (isset($_GET["filter_osver"])) {
$sql .= "osver = ? AND ";
$params.="s";
$params2.=', $_GET["filter_osver"]';
}
if (isset($_GET["filter_user_agent"])) {
$sql .= "user_agent = ? AND ";
$params.="s";
$params2.=', $_GET["filter_user_agent"]';
}
if (isset($_GET["filter_username"])) {
$sql .= "username = ? AND ";
$params.="s";
$params2.=', $_GET["filter_username"]';
}
if (isset($_GET["filter_message"])) {
$sql .= "message = ? AND ";
$params.="s";
$params2.=', $_GET["filter_message"]';
}
if (isset($_GET["filter_app_name"])) {
$sql .= "app_name = ? AND ";
$params.="s";
$params2.=', $_GET["filter_app_name"]';
}
$sql.="1";
//echo "\$params: ".$params."<br>";
//echo "\$params2: ".$params2."<br>";
//echo "<br>\$stmt->bind_param(\$params$params2);<br>";
//echo var_dump($_GET);
$stmt = $conn->prepare($sql);
exec("\$stmt->bind_param(\$params$params2);");
if ($stmt->execute()) {
//echo "<br>Success!";
} else {
//echo "<br>Failure: ".$stmt->error;
}
$result = $stmt->get_result();
$out = array();
while ($row = $result->fetch_assoc()) {
array_push($out, $row);
}
echo json_encode($out);
This code works perfectly when no filters are specified - however, when any filter is specified, the statement fails with the error No data supplied for parameters in prepared statement. I have verified that the code in the exec() should be (for example, if the user_agent filter is set) $stmt->bind_param($params, $_GET["filter_user_agent"]);
Additionally, the SQL query works perfectly when I use the query but just manually replace the ?s with the filters, so it does not appear to be a problem with the initial query, but rather the prepared statement. Help would be much appreciated.
NB: The commented out echos are for debug purposes, and are usually disabled, but I have left them in to show how I got the information that I currently have.
EDIT: Answered my own question below - the error was that I was using exec() - a function which executes external shell commands, whereas what I wanted was eval(), which evaluates a string input and the executes it as a PHP script.
Turns out I was simply mistaken as to the function of exec(). (Too much Python?) exec() runs an external shell command, whereas what I was looking for was eval() which evaluates and runs any string inputted as PHP code.
Looks like you never actually use the values $params and $params2. You concatenate them, but where is your $stmt->bind_param()? It's commented out?
I don't see a $conn->prepare("") either. Did you omit some code?
$conn is defined as a mysqli object and then again never used. Something's not right here.
Edit:
Try exec("\$stmt->bind_param(\$params\$params2);"); I assume you somehow execute the code and escape the variables - following that logic you should escape both params and params2, perhaps?
This question already has answers here:
Can I bind an array to an IN() condition in a PDO query?
(23 answers)
Closed 8 years ago.
This is my code:
if(isset($_POST['abc']))
{
$things['abc'] = mysqli_real_escape_string($connect, implode("','", $_POST['abc']));
$result = mysqli_query($connect, "SELECT * FROM this_list WHERE abc_column IN ('{$things['abc']}')");
if (!$result)
{
echo "Error fetching results: " . mysqli_error();
}
else
{
while ($row = mysqli_fetch_array($result))
{
$abc[] = $row['description'];
}
}
}
The above code uses mysqli_real_escape_string(), and $things is an array with checkbox values that is received via POST. This array contains the list of strings separated by comma that I am using in the query.
When I was searching on the net, I noticed that some people say mysqli_real_escape_string() may prevent sql injection, I was thinking maybe prepared statement for checkbox values might be more safer against sql injection.
I have used prepared statement with separate parameters to prevent sql injection. But I am stuck on this one and I dont know how to change the above code to a prepare() statement since it uses an array $things['abc']. I tried searching and everytime I search array in prepared statement, I am getting info on Java, etc.. Can someone enlighten me on how I can do this with php please?
EDIT:
After the help from onetrickpony code below, this is what I have now:
if(isset($_POST['abc']))
{
$ph = rtrim(str_repeat('?,', count($_POST['abc'])), ',');
$query = sprintf("SELECT col1 FROM abc_table WHERE col2 IN (%s)", $ph);
$stmt = mysqli_prepare($connect, $query);
// bind variables
$params = array();
foreach($_POST['abc'] as $v)
$params[] = &$v;
array_unshift($params, $stmt, str_repeat('s', count($_POST['abc']))); // s = string type
call_user_func_array('mysqli_stmt_bind_param', $params);
mysqli_stmt_execute($stmt);
// Get the data result from the query.
mysqli_stmt_bind_result($stmt, $col1);
/* fetch values and store them to each variables */
while (mysqli_stmt_fetch($stmt)) {
$name[] = $col1;
echo $name;
}
//loop to echo and see whats stored in the array above
foreach($name as $v) {
echo $v;
}
// Close the prepared statement.
$stmt->close();
}
In the above code, the sqli method for prepare statement seems to work which is great. However, when I use the mysqli_stmt_bind_result(), the $name[] array inside the while loop only seems to print the last row.
UPDATE:
onetrickpony's code with the mysqli method for using php array in a Prepared Statement worked fine and it was a very good approach he had suggested. However, I have been having nightmare with the second half of the code which is trying to get the fetched array results to work. After trying for more than a day, I have given up on that and I have made the switch to PDO. Again onetrickpony's advise below was totally worth it. Making the switch to PDO made the code so much easier and simpler and couldnt believe it.
Try this:
// build placeholder string (?,?...)
$ph = rtrim(str_repeat('?,', count($_POST['abc'])), ',');
$query = sprintf("SELECT * FROM this_list WHERE abc_column IN (%s)", $ph);
$stm = mysqli_prepare($connect, $query);
// bind variables (see my notes below)
$params = array();
foreach($_POST['abc'] as $v)
$params[] = &$v;
// s = string type
array_unshift($params, $stm, str_repeat('s', count($_POST['abc'])));
call_user_func_array('mysqli_stmt_bind_param', $params);
mysqli_stmt_execute($stm);
It appears that mysqli_stmt_bind_param cannot be called multiple times to bind multiple variables. And even worse, it requires referenced variables. I'd recommend you switch to PDO, just because of these limitations that force you to write ugly code :)