New to this new and secure way of handling SQL's in PHP and MySql driven web based application, to secure the code from SQL injections. I am planning to start using mysqli with PDO. Can anyone please outline how should i get started and proceed.
Any reference to any article will also be helpful.
Thanks in advance.
To create the connection
try {
$db = new PDO("mysql:dbname=".DB_NAME.";host=".DB_HOST,DB_USER,DB_PWD);
} catch (PDOException $e) {
die("Database Connection Failed: " . $e->getMessage());
}
Then to prepare a statement
$prep = $db->prepare("SELECT * FROM `users` WHERE userid = ':id'");
As you can see, you label each parameter you'd like by prefixing any string with ':'. Then all you do is pass an array mapping the parameter (:id) to the value when you execute.
if (!$prep->execute(array(":id" => $userinput))) {
$error = $prep->errorInfo();
echo "Error: {$error[2]}"; // element 2 has the string text of the error
} else {
while ($row = $prep->fetch(PDO::FETCH_ASSOC)) { // check the documentation for the other options here
// do stuff, $row is an associative array, the keys are the field names
}
}
Instead of PDO::FETCH_ASSOC with the "fetch" function, there are various other ways to get your data. You can use fetchAll to get an array of ALL the results at once instead of just going row by row. Or you can get the array of information as a 0-indexed array, or you can even fetch the results directly into a class instance (if the field names line up with the properties of the class.)
All the documentation of PDO can be found here: PHP.net PDO Manual
Related
I'm developing a web based software that uses MySQL and PHP on the backend.
I'm trying to obtain data with a complex query and in the end I just obtain the query.
function consulttimes(){
$pdo = connect();
try{
$consult = $pdo->prepare("SELECT credentials.realname, timestamp_greenhouse.* FROM times.credentials, times.timestamp_greenhouse WHERE timestamp_greenhouse.id = credentials.id;");
$consult->execute();
$consult->fetch(PDO::FETCH_ASSOC);
echo json_encode($consult);
//file_put_contents('times.json', $json);
}
catch(PDOException $e) {
echo $e -> getMessage();
}
}
I have all the databases and the query works perfectly on phpmyadmin.
Can someone help me with this?
Cheers!
I'm trying to obtain data with a complex query and in the end I just obtain the query.
The problem is because of this line,
echo json_encode($consult);
$consult is a PDOStatement object returned from the prepared statement. I believe you're trying to encode the row obtained from ->fetch(PDO::FETCH_ASSOC) method.
So first fetch the row from the result set, store it in a variable and then apply json_encode on it, like this:
// your code
$consult->execute();
$result = $consult->fetch(PDO::FETCH_ASSOC);
echo json_encode($result);
I'm trying to implement pagination using PHP. I found that calling exec to the connected database prevents the further query calls from working.
The piece of code at hand:
<?php
// Pagination logic
//Here we count the number of results
$query = "SELECT COUNT(*) as num FROM gig";
$total_pages = $db->exec($query);
$total_pages = $total_pages[num];
?>
After it if I try to use a query such as:
<?php>
foreach ($db->query("SELECT sname, start, venue FROM gig WHERE start = '0000-00-00 00:00:00'") as $a) {
$row="<tr><td>$a[sname]</td><td>To be announced</td><td>$a[venue]</td></tr>\n";
print $row;
}
?>
it returns
Warning: Invalid argument supplied for foreach()
As soon as the first code block is removed, the query works fine. When I check the value of $total_pages, it's 0, so something must be going wrong along the way. As far as I know, I use it in the same way as the query(which works on its own), so is there any reason why it doesn't work?
The PDO is initialized in the following way:
try {
$db = new PDO("mysql:dbname=$db_name;host=$db_server", $db_user, $db_pw);
} catch (PDOException $e) {
die('Connection failed: ' . $e->getMessage());
}
session_start();
From Manual
PDO::exec() does not return results from a SELECT statement. For a
SELECT statement that you only need to issue once during your program,
consider issuing PDO::query(). For a statement that you need to issue
multiple times, prepare a PDOStatement object with PDO::prepare() and
issue the statement with PDOStatement::execute().
Used a function of the STATEMENT object had after using querying to count the rows instead of exec:
$dbq = $db->query("SELECT * FROM gig");
$rows = $dbq->rowCount();
About the latter code block not working because of the exec failing - it seems to just be the way php queries work, if one fails, all fail. The foreach() error is for the object it's provided is not an array, for it failed.
I am new to the php fat-free framework, and I am trying figure out how to loop through my mysql query results, or better yet, get it as an associative array (for learning purposes only).
What I did so far is
while(!$users->dry()){
array_push($user_assoc,$users->cast());
$users->next();
}
This works, but I was wondering if there is a better way of doing this? Also how do I setup a error handler? I mean how do I check if the query had any errors (i.e. fat-free equivalent of mysql_error())?
DB querying
There are 3 variants to loop through db results:
Without mapper:
Execute a SQL query and fetch the result set as an array of associative arrays:
$users = $db->exec('SELECT * FROM users');
foreach($users as $user)
echo $user['name'];//associative array
With mapper->load:
Fetch mapper rows one by one (your method):
$user=new \DB\SQL\Mapper($db,'users');
$user->load('');
while(!$user->dry()) {
echo $user->name;//db mapper
$user->next();
}
With mapper->find:
Fetch the result set as an array of mappers:
$mapper=new \DB\SQL\Mapper($db,'users');
$users=$mapper->find('');
foreach($users as $user)
echo $user->name;//db mapper
DB error handling
\DB\SQL is a subclass of PDO so it can throw catchable PDO exceptions. Since these are disabled by default, you need to enable them first. This can be done in 2 different ways:
at instantiation time, for all transactions:
$db = new \DB\SQL($dsn, $user, $pwd, array( \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION ));
later on in the code, on a per-transaction basis:
$db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
Once PDO exceptions are enabled, just catch them as other exceptions:
try {
$db->exec('INSERT INTO mytable(id) VALUES(?)','duplicate_id');
} catch(\PDOException $e) {
$err=$e->errorInfo;
//$err[0] contains the error code (23000)
//$err[2] contains the driver specific error message (PRIMARY KEY must be unique)
}
This also works with DB mappers, since they rely on the same DB\SQL class:
$db=new \DB\SQL($dsn,$user,$pwd,array(\PDO::ATTR_ERRMODE=>\PDO::ERRMODE_EXCEPTION));
$mytable=new \DB\SQL\Mapper($db,'mytable');
try {
$mytable->id='duplicate_id';
$mytable->save();//this will throw an exception
} catch(\PDOException $e) {
$err=$e->errorInfo;
echo $err[2];//PRIMARY KEY must be unique
}
You're already using the correct way. At least if you want to use the mapper. By using the SQL class directly, an associative array is returned. Mostly everything related to that is described here http://fatfreeframework.com/databases#querying-the-database
$result = $db->exec('SELECT * FROM users');
print_r($result);
If you're looking for errors or you want to know what has been executed, use $db->log();. http://fatfreeframework.com/databases#profiling
This yields proper results, but I would like to have the resulting row in an array, instead of binding individual variables to each field, so I can access fields like $row[0] and/or $row["name"].
$idToSearch = 2;
$conn = new mysqli("localhost", "username", "password", "db_people");
$statement = $conn->prepare("SELECT name, age from People where id = ?");
$statement->bind_param("i", $idToSearch);
$statement->execute();
$statement->bind_result($name, $age);
if($statement->fetch()) {
echo "The name is $name and the age is $age. ";
} else {
echo "No person found with that id.";
}
Saw an example about fetch_assoc(), but it used a mysqli_result class which I don't know hot to use and unprepared statements which I'd rather not use.
EDIT: To clarify, I'm fine with a solution whether it uses bind_result or not.
In order to use fetch_assoc you would need to use get_results which would force you to not use the bind which it seems you don't want to do. So I believe what you want to do is explained pretty well by user uramihsayibok in the php docs for the bind_result function, specifically here: http://php.net/manual/en/mysqli-stmt.bind-result.php#92505. They explain how to work around that in order get the results into an array.
I create my prepared statement as:
pg_prepare('stm_name', 'SELECT ...');
Today, I had a problem (calling twice a function for mistake) when declaring a prepared statement with the same name twice:
Warning: pg_prepare() [function.pg-prepare]: Query failed: ERROR: prepared statement "insert_av" already exists in xxx on line 221
So, as the question title, there is a way to check if a prepare statement with the same label already exists, and in case, overwrite it?
I know this error is from my mistake and will be solved by simply declaring the prepared statements at the begin of my code, but I'm wondering if there is a solution to have more control over them.
EDIT:
After the Milen answer, is quite simply to check if the prepared statement is already in use, simply querying the db for the table pg_prepared_statements:
try{
$qrParamExist = pg_query_params("SELECT name FROM pg_prepared_statements WHERE name = $1", array($prepared_statement_name));
if($qrParamExist){
if(pg_num_rows($qrParamExist) != 0){
echo 'parametized statement already created';
}else{
echo 'parametized statement not present';
}
}else{
throw new Exception('Unable to query the database.');
}
}catch(Exception $e){
echo $e->getMessage();
}
But, I don't think this is a good solution, because i have to query the database every time.
Ok, usually the prepared statements are declared in the begin of the script and then just reused, but, I have a class nicely wired and I don't like to declare 10 prepared statements when I'll use just 3 of them.
So, I think I'll use a simple PHP array to keep track the statements I create, and then with isset() function check if it exists or needs to be created:
try{
$prepare = pg_prepare('my_stmt_name', "SELECT ...");
if($prepare){
$this->rayPrepared['my_stmt_name'] = true;
}else{
throw new Exception('Prepared statement failed.');
}
}catch(Exception $e){
echo $e->getMessage();
}
One way (I hope someone will point out a simpler one):
<?
$prepared_statement_name = 'activity1';
$mydbname = '...';
$conn = pg_connect("host=... port=... dbname=... user=... password=...");
$result = pg_query_params($conn, 'SELECT name FROM pg_prepared_statements WHERE name = $1', array($prepared_statement_name));
if (pg_num_rows($result) == 0) {
$result = pg_prepare($conn, $prepared_statement_name, 'SELECT * FROM pg_stat_activity WHERE datname = $1');
}
$result = pg_execute($conn, $prepared_statement_name, array($mydbname));
while($row = pg_fetch_row($result)) {
var_dump($row);
}
Haven't tried this in php but if this is feasible in your application (if you need the statement only in one place and don't have to "fetch" it again by name) you could try to prepare an unnamed statement.
http://www.postgresql.org/docs/8.4/interactive/libpq-exec.html says:PQprepare
...stmtName may be "" to create an unnamed statement, in which case any pre-existing unnamed statement is automatically replaced; otherwise it is an error if the statement name is already defined in the current session.php_pg uses PQprepare, so this might work for you.
Why are you using prepared statements at all ? They only offer a performance advantage if you use the same statement many times over.