PDO prepared statements in functions [duplicate] - php

This question already has answers here:
How do I loop through a MySQL query via PDO in PHP?
(3 answers)
Closed 9 years ago.
I am currently using MySQL with PHP but am looking to start MySQLi or PDO
I have while loops like:
$sql="select from ... ";
$rs=mysql_query($sql);
while($result=mysql_fetch_array($rs))
{
$sql2="select from table2 where id = $result["tbl1_id"] ";
}
If I put my MySQLi or PDO queries into a function how can I run things like the above? Doing while loops with queries inside the while loops?
Or is if easier to not do the functions at all and just run the prepared statements as normal?

You wouldn't. And to be honest.. Even in the old days you would not do it this way, but like this:
$sql="select from ... ";
$rs=mysql_query($sql);
$ids = array()
while($result=mysql_fetch_array($rs))
{
$ids[] = $result["tbl1_id"];
}
$sql2="select from table2 where id in ".implode(',', $ids) .";
Or even better, you use a join to run the query just once, on all the tables that need to provide info.
In PDO you can do the same thing. Get all the ID's and the execute a query

I usually take the approach of preparing the query and not using a function. Also I am not clear as to what exactly it is that you want. You want to make your queries as quick and efficient as possible so you should not look to run a while look within another while loop.
This is how my PDO queries usually look
My connection:
$host = "localhost";
$db_name = "assignment";
$username = "root";
$password = "";
try {
$connection = new PDO("mysql:host={$host};dbname={$db_name}", $username, $password);
}catch(PDOException $exception){ //to handle connection error
echo "Connection error: " . $exception->getMessage();
}
MY query:
$query = "SELECT * FROM Table";
$stmt = $connection->prepare( $query );
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
extract($row);
}

It's a duplication question like oGeez say, you have to learn how to code PDO in PHP and other before asking question,
this is the answer:
$dbh = new PDO("mysql:host=" . HOST . ";dbname=" . BASE, USER, PASS, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = 'SELECT * FROM table';
$stmt = $dbh->query($query);
$items = $stmt->fetchAll(PDO::FETCH_OBJ);
foreach($items as $item {
print_r($item);
}

the main reason to put it in a function would be if you use the query in multiple files. i have a web app with many queries and i like to keep them in a separate file so that they're easier to track down if i need to make changes. the main thing is that you 1) have to pass your database as a parameter and 2) return the results
function pdoquery($db, $parameter){
$query = "SELECT * FROM table WHERE column=?";
$stmt = $db->prepare($query);
$stmt->bindValue(1, $parameter, PDO::PARAM_STR); //or PARAM_INT
if (!$stmt->execute()) {
echo "Could not get results: (" . $stmt->errorCode . ") " . $stmt->errorInfo;
exit;
}
else
$result = $stmt->fetch();
$db = null;
return $result;
}
but as others have mentioned, if its only used once, there's no need for a function, and looping through the results is best done outside of the function as well. however, it is possible to do it inside the function if you want to.

Related

Postgresql not binding in prepared statement for SELECT in PHP

<?php
try
{
global $db;
$user = 'postgres';
$password = '*****'; //For security
$db = new PDO('pgsql:host=localhost;dbname=dnd', $user, $password);
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch (PDOException $ex)
{
echo 'ERROR!!: ' . $ex->getMessage();
die();
}
$table = htmlspecialchars($_REQUEST['table']);
$idNum = htmlspecialchars($_REQUEST['id']);
try {
//$query = "SELECT * FROM $table WHERE id = $idNum"; This works
//$query = "SELECT * FROM $table WHERE id = :number"; This works
$query = "SELECT * FROM :tableName WHERE id = :number";
$statement = $db->prepare($query);
$statement->bindValue(":tableName", $table, PDO::PARAM_STR);
$statement->bindValue(":number", $idNum, PDO::PARAM_INT);
$statement->execute();
$info = $statement->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $excep) {
echo "Opps: " . $excep->getMessage();
die();
}
Okay I'm going crazy here trying to get this to work.
I have a database set up that I need to query from. I receive the query from an AJAX request with the name of the table I want and the id for the item. When I try to query with both variables, the binding does not occur in the prepared statement and instead I get this error code
Opps: SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "$1" LINE 1: SELECT * FROM $1 WHERE id = 1 ^
When I have just the straight PHP variables it works fine so I know it can work, but when I want to bind multiple it seems to fail and give a variable number as above.
I can also get it to work if I simply have one of the variables bound, such as the second commented out query in the code - this only works tho if I have the variable I want at the end and not if I wanted to lookup the table spot. (I.E.
$query = "SELECT * FROM :tableName WHERE id = $idNum"; does not work)
I need to cleanse the variables to prevent SQL injection, but I can't do that without binding the variables in a prepared statement. Any help would be appreciated!
According to the PHP manual you can't bind a tablename. As you mentioned it, you can replace it by a variable, but you can't replace it with a placeholder.
So the only solution that will work for you is the query you have above:
$query = "SELECT * FROM $table WHERE id = :number"
This will be what you're looking for. If you want to make it safe for injection, you have to find another way. (Regex for example).
Ref: http://us3.php.net/manual/en/book.pdo.php#69304

How to prevent weird user inputs from breaking things in queries?

Is there a good standard solution to deal with characters like ' and " from being used in user inputs on a web platform?
I'm using php for a webpage and if I have, for example, a search bar which have the following query behind it.
$sql = "select * from aTable where aColumn like '%".$searchedKeyword."%'";
If I search for like Greg's icecream the ' will break the script. Also, I'm guessing if I search for something like 1' or ID>0 my script will have a false effect.
What is the common solution here? Do you usually filter away undesired characters, or is there maybe some method or similiar built-in to php?
You can us PDO and prepared statements to prevent SQL injection.
http://php.net/manual/en/pdo.prepared-statements.php
$searchedKeyword = "mykeyword";
//Database details
$db = 'testdb';
$username = 'username';
$password = 'password';
//Connect to database using PDO (mysql)
try {
$dbh = new PDO('mysql:host=localhost;dbname='.$db, $username, $password);
} catch (PDOException $e) {
var_dump("error: $e");
}
//Prepared SQL with placeholder ":searchedKeyword"
$sql = "select * from aTable where aColumn like '%:searchedKeyword%'";
$sth = $dbh->prepare($sql);
//Bind parameter ":searchedKeyword" to variable $searchedKeyword
$sth->bindParam(':searchedKeyword', $searchedKeyword);
//Execute query
$sth->execute();
//Get results
$result = $sth->fetchAll(); //fetches all results where there's a match

How can I write a php code for data can not find in table of MySQL database?

I am so sorry mybe it is a silly question but as I am new in web language and php I dont know how to solve this problem.
I have a code which is getting ID from user and then connecting to MySQL and get data of that ID number from database table and then show on webpage.
But I would like to what should I add to this code if user enter an ID which is not in table of database shows a message that no data found.
Here is my code:
<?php
//connect to the server
$connect = mysql_connect ("localhost","Test","Test") ;
//connection to the database
mysql_select_db ("Test") ;
//query the database
$ID = $_GET['Textbox'];
$query = mysql_query (" SELECT * FROM track WHERE Code = ('$ID') ");
//fetch the results / convert results into an array
$ID = $_GET['Textbox'];
WHILE($rows = mysql_fetch_array($query)) :
$ID = 'ID';
echo "<p style=\"font-color: #ff0000;\"> $ID </p>";
endwhile;
?>
Thank You.
Sorry if it is so silly question.
You should use PDO (great tutorial here: http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers ). This way, you can develop safer applications easier. You need to prepare the ID before inserting it to the query string, to avoid any user manipulation of the mysql query (it is called sql injection, guide: http://www.w3schools.com/sql/sql_injection.asp ).
The main answer to your question, after getting the results, you check if there is any row in the result, if you got no result, then there is no such an ID in the database. If you use PDO statements $stmt->rowCount();.
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
$stmt = $db->prepare("SELECT * FROM table WHERE Code=?");
$stmt->bindValue(1, $id, PDO::PARAM_INT); // or PDO::PARAM_STR
$stmt->execute();
$row_count = $stmt->rowCount();
if ($row_count > 0) {
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
//results are in $results
} else {
// no result, no such an ID, return the error to the user here.
}
Another reason to not use mysql_* functions: http://php.net/manual/en/migration55.deprecated.php

how to optimize database connections for nested queries?

I am using nested queries to retrieve information from multiple tables. I need advice on optimizing this php code.
This function creates an object.
public function conn($query){
$mysqli = new mysqli('test','test','test','test');
$result = $mysqli->query("SET NAMES utf8");
$result = $mysqli->query("set character_set_client='utf8'");
$result = $mysqli->query("set collation_connection='utf8_general_ci'");
$result = $mysqli->query($query);
$mysqli->close();
return $result;
}
This code uses that function.
$connect = $this->conn("SELECT * FROM Table LIMIT 100000");
while($i = $connect->fetch_assoc()){
$name = $i["name"];
$connect2 = $this->conn("SELECT * FROM Names WHERE Name = '$name'");
if($connect2 ->num_rows > 0){
echo $name.'<br>';
}
}
Need recommendations for a connection to the database.
In the while loop, as you see, I am checking for the presence of $name in other table. But I am opening and closing a connection every time through the loop. And this will be 100001 connection opens and closes.
Is it possible to open a connection to the database only once?
P.S.: The SQL is an example - Please don't suggest changes there, because I am trying to figure out how to handle the repeated queries, not optimize the SQL.
Connection objects are reusable. Make a connection, then use it to make as many queries as you want. Close each query (that is, each result set) when you're done with it, then close the connection at the end of the run.
Closing a connection is a network operation, so it takes a while. Closing a query is mostly an in-memory operation, so it is faster.
In your example, you're using nested queries (more on that in a moment). Your code should end up looking something like this pseudocode:
public function getconn(){
$mysqli = new mysqli('test','test','test','test');
$mysqli->query("SET NAMES utf8");
$mysqli->query("set character_set_client='utf8'");
$mysqli->query("set collation_connection='utf8_general_ci'");
return $mysqli; /* return the connection handle */
}
$conn1 = getconn();
$conn2 = getconn();
$resultset1 = $conn1->query("SELECT * FROM Table LIMIT 100000");
while($i = $resultset1->fetch_assoc()){
$name = $i["name"];
$resultset2 = $conn2->query("SELECT * FROM Names WHERE Name = '$name'");
if($resultset2->num_rows > 0){
echo $name.'<br>';
}
$resultset2->close();
}
$resultset1->close();
$conn1->close();
$conn2->close();
(Please note; I haven't debugged this code.)
To take this optimization one step further, you should consider using a prepared statement for the query inside the while loop. Here's documentation on that http://php.net/manual/en/mysqli-stmt.fetch.php.
$conn1 = getconn();
$conn2 = getconn();
/* create a prepared statement with placeholder parameter ? */
$stmt = $mysqli->prepare("SELECT * FROM Name WHERE Name = ?"));
$name = '';
$name_out = '';
$stmt->bind_param("s", $name);
$stmt->bind_result($name_out);
$resultset1 = $conn1->query("SELECT * FROM Table LIMIT 100000");
while($i = $resultset1->fetch_assoc()){
$name = $i["name"];
$resultset2 = $stmt->execute(); /* run query with bound parameter */
if ($stmt_fetch() ( {
echo $name.'<br>';
}
$resultset2->close();
}
$resultset1->close();
$conn1->close();
$conn2->close();
(Please note; I haven't debugged this code either.)
Now, it's possible your pair of queries are just an example to show a set of nested queries. If so, that's fine. But, you are performing this task (retrieve 100K names) in an almost unimaginably inefficient way. You've said you don't want anybody to rewrite this query, but I am sorry, I can't just let this one pass.
This code would do a far more streamlined job.
$conn = getconn();
$q = "SELECT t.name FROM Table t JOIN Name n ON t.name = n.name LIMIT 100000";
$resultset = $conn->query($q);
while($i = $resultset->fetch_assoc()){
$name = $i["name"];
echo $name.'<br>';
}
$resultset->close();
$conn->close();
It's more efficient for two reasons. First, it doesn't use SELECT *, which ends up sending all sorts of data over the network from your MySQL server to your php program, just to throw it away.
Second, it doesn't use the nested queries. Instead, the JOIN query pulls all the name columns from Table that have a matching name column in Names.

Moving from MySQL to MySQLi

Could somebody please point me in the right direction. I am in the process of making the transition from MySql to MySqli. Normally I would select from the database using th code below and it would allow me to easily use the column value as a working variable:
$SQLCommand = "SELECT * FROM table WHERE column1 = 'ok'";
$Data = mysql_query($SQLCommand);
$DataRow = mysql_fetch_assoc($Data);
$var1 = $DataRow["column1"];
$var2 = $DataRow["column2"];
$var3 = $DataRow["column3"];
$var4 = $DataRow["column4"];
I have researched how to do the MySql equivalent but I find theres a lot of different way using loops etc. Is there a like for like (for want of a better description) that does the same thing? Thanks in advance.
Instead of going with the flow, i care to suggest a PDO alternative
$db = new PDO($dsn, 'username','password');
//$dsn is the connection string to your database.
//See documentation for examples
//The next two rows are optional, but i personally suggest them to
//ease developing, debugging (the 1st) and fetching results (the 2nd)
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $db->prepare("SELECT * FROM table WHERE column1 = :c1");
$stmt->bindValue(':c1', 'ok'); //This example is trivial and not necessary
//but it gains relevance when the bound value
//is a variable
$rows = $stmt->fetchAll(); //if you expect a single row use fetch() instead
//do something with the results
You can read more about PDO here: PDO manual
The biggest PDO advantage is that it's independent of the actual database in use by your application. If, by chance, you want to change database in the future, for example SQLITE or PostgreSQL, the only* change you have to make is your $dsn connection string
[*] True only if you used standard SQL queries and nothing vendor-specific.
A direct conversion would be:
$Data = mysqli_query($connection, $SQLCommand);
$DataRow = mysqli_fetch_assoc($Data);
The difference, other than the i is that mysqli_query requires the connection as an argument (as do most mysqli_* functions).
MySQLi also has an object oriented style:
$Data = $connection->query($SQLCommand); // assuming you created the $connection object
$DataRow = $data->fetch_assoc();
They should be like
$mysqli = new mysqli("localhost", "my_user", "my_password", "my_db");
$SQLCommand = "SELECT * FROM table WHERE column1 = 'ok'";
$Data = $mysqli->query($SQLCommand);
$DataRow = $mysqli->fetch_assoc($Data);
Try this LINK
My suggestion is to use mysqli prepared statement whenever you are using user inputs to prevent SQL injection:
See below code uses object oriented approach and prepared statement
<?php
$mysqli = new mysqli("example.com", "user", "password", "database");
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
!$mysqli->query("CREATE TABLE test(id INT, label CHAR(1))") ||
!$mysqli->query("INSERT INTO test(id, label) VALUES (1, 'a')")) {
echo "Table creation failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
/* Prepared statement, stage 1: prepare */
$stmt = $mysqli->prepare("SELECT id, label FROM test WHERE id = ?");
/* Prepared statement, stage 2: bind and execute */
$id = 1;
//note below "i" is for integer, "s" can be used for string
if (!$stmt->bind_param("i", $id)) {
echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error;
}
$stmt->execute();
$res = $stmt->get_result();
$row = $res->fetch_assoc();
printf("id = %s (%s)\n", $row['id'], gettype($row['id']));
printf("label = %s (%s)\n", $row['label'], gettype($row['label']));
?>

Categories