Creating a container function for a PDO query in PHP - php

Because I find PDO executions extremely hard to remember and find myself looking back at previous projects or other websites just to remember how to select rows from a database, I decided that I would try and create my own functions that contain the PDO executions and just plug in the data I need. It seemed a lot simpler than it actually is though...
So far I have already created a connect function successfully, but now when it comes to create a select function I'm stumped for multiple reasons.
For starters there could be a variating amount of args that can be passed into the function and secondly I can't figure out what I should pass to the function and in which order.
So far the function looks like this. To keep me sane, I've added the "id" part to it so I can see what exactly I need to accomplish in the final outcome, and will be replaced by variables accordingly when I work out how to do it.
function sql_select($conn, **what to put here**) {
try {
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
$result = $stmt->fetchAll();
if ( count($result) ) {
foreach($result as $row) {
print_r($row);
}
} else {
return "No rows returned.";
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
}
So far what I've established that the function will need to do is
Connect to the database (using another function to generate the $conn variable, already done)
Select the table
Specify the column
Supply the input to match
Allow for possible args such as ORDER by 'id' DESC
Lastly from this I would need to create a function to insert, update and delete rows from the database.
Or, is there a better way to do this rather than functions?
If anyone could help me accomplish my ambitions to simply simplify PDO executions it would be greatly appreciated. Thanks in advance!

First of all, I have no idea where did you get 10 lines
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = ?');
$stmt->execute(array($id));
$result = $stmt->fetchAll();
is ALL the code you need, and it's actually three lines, which results with a regular PHP array that you can use wherever you wish. Without the need of any PDO code. Without the need of old mysql code.
Lastly from this I would need to create a function to insert, update and delete rows from the database.
DON'T ever do it.
Please read my explanations here and here based on perfect examples of what you'll end up if continue this way.
accomplish my ambitions to simply simplify PDO executions
That's indeed a great ambition. However, only few succeeded in a real real simplification, but most resulted with actually more complex code. For starter you can try code from the first linked answer. Having a class consists of several such functions will indeed improve your experience with PDO.

. . . and find myself looking back at previous projects or other
websites just to remember how to select rows from a database . . .
FYI, we all do that.
You had a problem with the PDO API and now you have two problems. My best and strongest suggestion is this: If you want a simpler/different database API, do not roll your own. Search http://packagist.org for an ORM or a DBAL that looks good and use it instead of PDO.
Other people have already done this work for you. Use their work and focus instead on whatever awesome thing is unique to your app. Work smart, not hard and all that.

Writting a wrapper, should start form connecting the DB, and all the possible method could be wrapped. Passing connection to the query method, doesn't look good.
A very rough example would be the code bellow, I strongly do not suggest this mixture, but it will give you the direction.
You connection should be made either from the constructor, or from another method called in the constructor, You can use something like this:
public function __construct($driver = NULL, $dbname = NULL, $host = NULL, $user = NULL, $pass = NULL, $port = NULL) {
$driver = $driver ?: $this->_driver;
$dbname = $dbname ?: $this->_dbname;
$host = $host ?: $this->_host;
$user = $user ?: $this->_user;
$pass = $pass ?: $this->_password;
$port = $port ?: $this->_port;
try {
$this->_dbh = new PDO("$driver:host=$host;port=$port;dbname=$dbname", $user, $pass);
$this->_dbh->exec("set names utf8");
} catch(PDOException $e) {
echo $e->getMessage();
}
}
So you can either pass connection credentials when you instantiate your wrapper or use default ones.
Now, you can make a method that just recieves the query. It's more OK to write the whole query, than just pass tables and columns. It will not make a whole ORM, but will just make the code harder to read.
In my first times dealing with PDO, I wanted everything to be dynamically, so what I achieved, later I realized is immature style of coding, but let's show it
public function query($sql, $unset = null) {
$sth = $this->_dbh->prepare($sql);
if($unset != null) {
if(is_array($unset)) {
foreach ($unset as $val) {
unset($_REQUEST[$val]);
}
}
unset($_REQUEST[$unset]);
}
foreach ($_REQUEST as $key => $value) {
if(is_int($value)) {
$param = PDO::PARAM_INT;
} elseif(is_bool($value)) {
$param = PDO::PARAM_BOOL;
} elseif(is_null($value)) {
$param = PDO::PARAM_NULL;
} elseif(is_string($value)) {
$param = PDO::PARAM_STR;
} else {
$param = FALSE;
}
$sth->bindValue(":$key", $value, $param);
}
$sth->execute();
$result = $sth->fetchAll();
return $result;
}
So what all of these spaghetti does?
First I though I would want all of my post values to be send as params, so if I have
input name='user'
input name='password'
I can do $res = $db->query("SELECT id FROM users WHERE username = :user AND password = :password");
And tada! I have fetched result of this query, $res is now an array containing the result.
Later I found, that if I have
input name='user'
input name='password'
input name='age'
In the same form, but the query remains with :user and :password and I submit the form, the called query will give mismatch in bound params, because the foreach against the $_REQUEST array will bind 3 params, but in the query I use 2.
So, I set the code in the beginning of the method, where I can provide what to exclude. Calling the method like $res = $db->query("SELECT id FROM users WHERE username = :user AND password = :password", 'age'); gave me the possibility to do it.
It works, but still is no good.
Better have a query() method that recieves 2 things:
The SQL string with the param names
The params as array.
So you can use the foreach() logic with bindValue, but not on the superglobal array, but on the passed on.
Then, you can wrap the fetch methods
public function fetch($res, $mode = null)
You should not directly return the fetch from the query, as it might be UPDATE, INSERT or DELETE.
Just pass the $res variable to the fetch() method, and a mode like PDO::FETCH_ASSOC. You can use default value where it would be fetch assoc, and if you pass something else, to use it.
Don't try to be so abstract, as I started to be. It will make you fill cracks lately.

Hum... IMHO I don't think you should try to wrap PDO in functions, because they're already "wrapped" in methods. In fact, going from OOP to procedural seems a step back (or at least a step in the wrong direction). PDO is a good library and has a lot of methods and features that you will surely lose if you wrap them in simple reusable functions.
One of those features is the BeginTransaction/Rollback (see more here)
Regardless, In a OOP point of view you can decorate the PDO object itself, adding some simple methods.
Here's an example based on your function
Note: THIS CODE IS UNTESTED!!!!
class MyPdo
{
public function __construct($conn)
{
$this->conn = $conn;
}
public function pdo()
{
return $this->conn;
}
public function selectAllById($table, $id = null)
{
$query = 'SELECT * FROM :table';
$params = array('table'=>$table);
if (!is_null($id)) {
$query .= ' WHERE id = :id';
$params['id'] = $id;
}
$r = $this->conn->prepare($query)
->execute($params)
->fetchAll();
//More stuff here to manipulate $r (results)
return $r;
}
public function __call($name, $params)
{
call_user_func_array(array($this->conn, $name), $params);
}
}
Note: THIS CODE IS UNTESTED!!!!
ORM
Another option is using an ORM, which would let you interact with your models/entities directly without bothering with creating/destroying connections, inserting/deleting, etc... Doctrine2 or Propel are good bets for PHP.
Howeveran ORM is a lot more complex than using PDO directly.

Related

Converting regular mysql into prepared statements

Im new to database and i have written a LOT of PHP code that accesses a database using MySQL.
I didnt take into account SQL injection attacks so i have to re-write all that PHP code to use mysql prepared statements.
After looking at videos on how to used prepared SQL statements, to perform just ONE SQL command requires a whole lot of "prepared" statements. My existing code has lots of different SQL statements all over the place, it would be a nightmare to change all that code to pack and unpack all the required preparation for each "prepared" statement command.
Is there some kind of wrapper i can use to prevent turning one line of regular SQL into 6 or 7 lines of prepared statements?
For example use to do this line line of SQL
SELECT * from users where userid=10
needs many more lines of prepared SQL statements, especially if there are lots of other SQL statements too it now becomes very complex.
Is there was some sort of one line wrapper that i can call that accepts the template SQL string, plus the parameters, which also executes the command and returns the result in just one line of wrapper for different types of MYSQL statements it would be great and the code would be much less confusing looking and error prone.
For example
$users=WrapAndExecute($db,"SELECT * from users where userid=?","s",$userid);
$data=WrapAndExecute($db,"UPDATE table SET username=?,city=?","ss",$name,$city);
$result=WrapAndExecute($db,"DELETE from table where id=?","s",$userid);
$result=WrapAndExecute($db,"INSERT into ? (name,address) VALUES(?,?)","ss","users",$name,$address);
Each of those lines above would create a prepared statement template, do the bind, execute it and return the result that a regular MYSQL statement would. This would create minimal impact on existing code.
Anybody knows how to do this or if some easy php library or class already exists to do this, that i can just import and start using it?
Thanks
You don't need to change a query to a prepared statement if it has no PHP variables in it. If it has just constant expressions, it's safe from SQL injection.
$sql = "SELECT * from users where userid=10"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
You don't need to change a query that contains PHP variables, as long as the value of that variable is a constant specified in your code. If it doesn't take its value from any external source, it's safe.
$uid = 10;
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
You don't need to change a query that contains PHP variables, as long as you can filter the value to guarantee that it won't risk an SQL injection. A quick and easy way to do this is to cast it to an integer (if it's supposed to be an integer).
$uid = (int) $_GET['uid'];
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
That leaves cases where you are using "untrusted" values, which may have originated from user input, or reading a file, or even reading from the database. In those cases, parameters are the most reliable way to protect yourself. It's pretty easy:
$sql = "SELECT * from users where userid=?"; // Safe!
// two lines instead of the one line query()
$stmt = $pdo->prepare($sql);
$stmt->execute([$_GET['uid']]);
$data = $stmt->fetchAll();
In a subset of cases, you need one additional line of code than you would normally use.
So quit your whining! ;-)
Re your comment about doing prepared statements in mysqli.
The way they bind variables is harder to use than PDO. I don't like the examples given in http://php.net/manual/en/mysqli.prepare.php
Here's an easier way with mysqli:
$sql = "SELECT * from users where userid=?"; // Safe!
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $_GET['uid']);
$stmt->execute();
$result = $stmt->get_result();
$data = $result->fetch_all();
I don't like the stuff they do in their examples with bind_result(), that's confusing and unnecessary. Just use get_result(). So with mysqli, you need two more lines of code than you would with PDO.
I've written query wrappers for mysqli that emulate the convenience of PDO's execute() function. It's a PITA to get an array mapped to the variable-arguments style of bind_param().
See the solution in my answers to https://stackoverflow.com/a/15933696/20860 or https://stackoverflow.com/a/7383439/20860
I were in the same boat, and I wrote such a wrapper that works exactly the way you want, save for it's being a class, not a function.
$user = $sdb->getRow("SELECT * from users where userid=?s", $userid);
$sdb->query("UPDATE table SET username=?s, city=?s", $name, $city);
$sdb->query("DELETE from table where id=?s", $userid);
$sdb->query("INSERT into ?n (name,address) VALUES(?s,?s)","users", $name, $address);
The above is a working code, as long as you have somewhere in your bootstrap file
$db = mysqli_connect(...);
...
require 'safemysql.class.php';
$sdb = new SafeMySQL('mysqli' => $db);
Note that none of the other suggestions could do anything like that.
Also note that if I were writing it today, I would have used PDO, as this class is duplicating a lot of functionality already exists in PDO.
Take a look at the PDO extension in PHP - http://php.net/manual/en/intro.pdo.php: it it secure against injections thanks to prepared statements; also, it allows you to connect to many different databases (e.g. MySQL, MSSQL, etc.).
You can then build your own wrapper as you wish to keep it clean; for example your own wrapper could be as follows:
(following example will return user rows as objects)
// connect to DB
$GLOBALS['default_db'] = new DB('localhost','db_name','username','password') ;
// Get users and output results
$query = new DBQuery('SELECT * FROM users WHERE userid = ?',array(10)) ;
var_dump($query -> results()) ;
var_dump($query -> num_rows()) ;
// DB connection
class DB {
public $connection;
public function __construct($host , $dbname , $username , $password) {
$this->connection = new \PDO('mysql:host=' . $host . ';dbname=' . $dbname , $username , $password);
}
}
// Wrapper
class DBQuery {
private $num_rows = 0;
private $results = array();
public function __construct($query , $params = null , $class_name = null , DB $db = null) {
if ( is_null($db) ) {
$db = $GLOBALS['default_db'];
}
$statement = $db->connection->prepare($query);
$statement->execute($params);
$errors = $statement->errorInfo();
if ( $errors[2] ) {
throw new \Exception($errors[2]);
}
$fetch_style = ($class_name ? \PDO::FETCH_CLASS : \PDO::FETCH_OBJ);
$this->results = $class_name ? $statement->fetchAll($fetch_style , $class_name) : $statement->fetchAll($fetch_style);
$this->num_rows += $statement->rowCount();
while ( $statement->nextrowset() ) {
$this->results = array_merge($this->results,$class_name ? $statement->fetchAll($fetch_style , $class_name) : $statement->fetchAll($fetch_style));
$this->num_rows += $statement->rowCount();
}
}
public function num_rows() {
return $this->num_rows;
}
public function results() {
return $this->results;
}
}
Since a key requirement seems to be that you can implement this with minimal impact on your current codebase, it would have been helpful if you had told us what interface you currently use for running your queries.
While you could use PDO:
that means an awful lot of work if you are not already using PDO
PDO exceptions are horrible
Assuming you are using procedural mysqli (and have a good reason not to use mysqli_prepare()) its not that hard to write something (not tested!):
function wrapAndExecute()
{
$args=func_get_args();
$db=array_shift($args);
$stmt=array_shift($args);
$stmt_parts=explode('?', $stmt);
if (count($args)+1!=count($stmt_parts)) {
trigger_error("Argument count does not match placeholder count");
return false;
}
$real_statement=array_shift($stmt_parts);
foreach ($args as $k=>$val) {
if (isnull($val)) {
$val='NULL';
} else if (!is_numeric($val)) {
$val="'" . mysqli_real_escape_string($db, $val) . "'";
}
$real_statement.=$val . array_shift($stmt_parts);
}
return mysqli_query($db, $real_statement);
}
Note that this does not handle IS [NOT] NULL nicely nor a literal '?' in the statement nor booleans (but these are trivial to fix).

Using database class with PDO [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
The classic first liner - have seen similar questions on SO but none that truly help me understand the crossroads I am at.
A little background before the code - I am not new to PHP or PDO (though not an expert either), but am a complete newbie to Object Oriented PHP and am trying to get the balance right of when to use classes and when it is possibly overkill.
The answer I'm hoping is in two parts. Firstly, it is good practice to create a wrapper database class when using PDO - for connection, basic queries etc.
Secondly, if not - are there better ways to speed up query writing?
EDIT Whilst I am questioning the code below, really I am question the PDO wrapper class approach overall - so the class below could be much larger than this, but is there any need/benefit?
See the following code;
NOTE: The class file is called via spl_autoload_register() in config.php
class_database.php
class Database
{
private $conn;
public function __construct() {
$this->openConnection();
}
public function openConnection() {
try {
$this->conn = new PDO('mysql:host=' . DB_SERVER . '; dbname=' . DB_NAME, DB_USER, DB_PASS);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'There was an error connecting to the database, Error: ' . $e->getMessage();
die();
}
}
public function getAll($sql, array $params) {
$stmt = $this->conn->prepare($sql);
$stmt->execute($params);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
}
generic_file.php
require_once '../includes/config.php';
$dbh = new Database();
$sql = ("SELECT * FROM users where id = :id and username = :username");
$id = 1;
$username = 'craig';
$params = array(':id' => $id,
':username' => $username);
$row = $dbh->getAll($sql, $params);
var_dump($row);
Now, to me this seems totally pointless. Using PDO alone, not a wrapper class, this query would be just as simple to write. On top of this - what if I want to use different fetch methods - I'd have to write more methods in the class.
Also, previously I have used a simple function to instantiate and return a new PDO object, simply including that file and assigning a variable to the function return was simple as quick - again I feel the class method is overkill.
Also, with my code above, and by doing this in a class, am I not losing the benefit of 'preparing' the statement as I will have to pass the sql statement in each time, even just to change the variables for the same statement?
However, I find lots of examples online, and especially on Lynda.com which I am using currently, of database wrapper classes. On top of this - I am no expert, and therefore what I feel is overkill may actually be best practice and strongly recommended, hence looking to you SO experts to help me out!
So...back to my question - is there a good reason to use such a class when using PDO?
If not, is there another DRY method that others use to minimize lines of codes needed for queries using PDO?
Thanks in advance.
I had your same question at one time.
The benefit to abstracting the database away is you can assure all connections are made correctly and if you ever do need to change the type of database there is only one spot that you need to change the code for. It also makes it easier to check the queries issued because you know if you echo and exit in the class all of the queries will able to be checked.
The way I solved it was by creating a class where the constructer established the connection and assigned it to a private variable while also setting the table in the database too.
The best way is to then have a few public functions to create, retrieve, update, and delete. Which is sometimes called CRUD.
For each function the only and first parameter is an array. For creating it takes the array and creates a prepared statement with it and then executes it.
It does a very similar thing with the others but for retrieve the array is what is being matched, for update it takes the things ending in id and sets the rest to update where the id = provided, and for delete it deletes where all of the keys = value in the table.
EDIT:
Here is the delete function I put in the class. If one of the parameter's values is an array it will prepare the statement and cycle through it. That is only for one variable changing though. You could also have it where you pass an array with the values of the numerical indexes being an array of what you would want to insert though that is not how I set up my code.
public function delete($info) {
$dbh = $this->dbh;
if (isset($info['submit_action'])) unset($info['submit_action']);
$where = array();
foreach (array_keys($info) as $name) {
$where[] .= "$name = :$name";
}
//echo "DELETE FROM {$this->table_name} WHERE " . implode(" AND ", $where) . ";"; exit;
$data = $dbh->prepare("DELETE FROM {$this->table_name} WHERE " . implode(" AND ", $where) . ";");
foreach ($info as $name => $value) {
if ($array_value == $name) $data->bindParam(":$name", $array_info);
else $data->bindValue(":$name", trim($value));
}
foreach ($info as $name => $value) if (is_array($value)) { $array_value = $name; break; }
if (isset($array_value)) {
foreach ($info[$array_value] as $array_info) {
try {
$data->execute();
}
catch (PDOException $e) {
if (!is_null($this->error_msg))
handle_error($this->error_msg, $e->getMessage());
else
handle_error("There was a problem removing the {$this->subject}.", $e->getMessage());
}
}
} else {
try {
$data->execute();
}
catch (PDOException $e) {
handle_error(/*public error msg - could set this anyway you want*/, $e->getMessage());
}
}
// Send success msg
}

Database abstraction layer ontop of mysqli

when trying to build robust database code (table locking, transactions, etc) i am always annoyed by the mass of code that needs to be done.
For example a transaction out of two prepared statements where i want to delete a user and update something about him in an "actions" table:
Lock Table users, actions
Start a transaction (autocommit false)
Make a prepared statement for the deletion of a user
Check if statement is != false (cause it could have already failed at 3.
Bind param
Check errorState != "00000" on the statement (can also have failed at binding params)
execute statement
Check errorState != "00000" on the statement (can also have failed at executing)
get Result of statement
Close statement
Make a new prepared statement for update actions
Check if statement != false
bind params
check statement's errorState
execute
check statement's errorState
get result
close statement
check overall transaction state, if valid commit, if not valid rollback
unlock tables
set autocommit back to true
This is how i do it (maybe im doing it wrong?). And if i do it that way its a lot of work and annoying. So i thought automateing that stuff.
What i want is something like this:
$DB->startTransaction();
$DB->query($query);
$DB->query($query2);
$DB->query($query3);
$DB->endTransaction();
And internally the database abstraction layer ontop of mysqli will take care of table locking, prepared statements and transactions itself. Shouldn't we be able to automate this?
This is one of my attempts:
public function query($query, $table, $params = null) {
if($params == null) {
$this->connection->query("LOCK TABLES $table WRITE");
$query = str_replace("!", $table, $query);
$result = $this->connection->query($query);
$this->connection->query("UNLOCK TABLES");
return $result;
}
else {
if (!$this->checkParams($query, $params)) {
return false;
}
$this->connection->query("LOCK TABLES $table WRITE");
$query = str_replace("!", $table, $query);
$stmt = $this->connection->prepare($query);
if ($stmt != false) {
$typesString = "";
foreach ($params as $param) {
if (is_numeric($param)) {
$typesString .= "i";
} else if (is_double($param)) {
$typesString .= "d";
} else {
$typesString .= "s";
}
}
$finalParamArray = array($typesString);
$finalParamArray = array_merge($finalParamArray, $params);
call_user_func_array(array($stmt, "bind_param"), $this->ref($finalParamArray));
$this->checkStatement($stmt);
$stmt->execute();
$this->checkStatement($stmt);
$result = $stmt->get_result();
$stmt->close();
$this->connection->query("UNLOCK TABLES");
return $result;
}
$this->query("UNLOCK TABLES");
return false;
}
}
This would be callable like this:
$DB->query("DELETE FROM ! WHERE userID =?", "Users", array($userID));
I am however not feeling confident about this. I googled a bit and didn't find something like i want. So my question now is: Is something like i want actually possible (well it should be)? Am i doing it wrong?
EDIT:
I also have 2 other attempts of doing this, which look MUCH MORE complicated (300+ lines of code). I can post them as well, if you want. I am still however not satisfied with them and not confident if this is actually correct!
You are right there should be an easier way of doing this, and you are also correct to say that we need an abstraction layer on top of mysqli. It is not designed to be used on its own.
You do not need so many steps. In particular, you do not need to check the return code of each method. That should already eliminate 6 or more of your steps. You do not need to close a statement either.
There's no need to specify the type when binding. Just use string type all the time. Other types come in handy very rarely, almost never.
Some time ago I posted an example of what an abstraction layer on top of mysqli could look like.
class DBClass extends mysqli {
public function __construct(
$host = null,
$username = null,
$passwd = null,
$dbname = null,
$port = null,
$socket = null
) {
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
parent::__construct($host, $username, $passwd, $dbname, $port, $socket);
$this->set_charset('utf8mb4');
}
public function safeQuery(string $sql, array $params = []): ?array {
$stmt = $this->prepare($sql);
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;
}
}
This is far from perfect, but it shows the main idea. You can wrap a prepared statement in one single method. Simple prepare/bind/execute/get_result. Nothing more. It works with and without parameters.
In the constructor the 3 mandatory steps to opening a connection: switching error reporting, creating instance of mysqli and setting the correct charset.
If you want transactions, then you can use mysqli's begin_transaction() and commit(). They are simple enough and do not require abstraction.
I do not know why you feel you need to lock tables, but again this is a simple SQL statement and doesn't need to be abstracted.
$db = new DBClass('localhost', 'user', 'pass', 'test');
$db->safeQuery('LOCK TABLES users WRITE');
$db->begin_transaction();
$db->safeQuery('DELETE FROM users WHERE userID =?', [$userID]);
$db->safeQuery('DELETE FROM otherTable WHERE userID =?', [$userID2]);
$db->commit();
$db->safeQuery('UNLOCK TABLES');

PHP PDO: gets first column from query

I have a pretty stupid question, but I can't get it to work immediately.
How do I load only one field of the result array of a query into a session (array) using a single PDO statement?
I commented the missing code below:
public function getPermissions($user_role_id){
if(!isset($user_role_id) || empty($user_role_id)){
$_SESSION['user']['user_permissions'] = '';
}else{
$db = Database::get_database();
$query = "
SELECT
rp.role_id, rp.permission_id
FROM
role_permission_tbl rp
WHERE
rp.role_id = :role_id";
$query_params = array(
':role_id' => $user_role_id
);
try
{
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
die("Failed to run query: " . $ex->getMessage());
}
$row = $stmt->fetchAll();
if($row){
//I only want to retrieve the field "permission_id"
$_SESSION['user']['user_permissions'] = $row;
}else{
$_SESSION['user']['user_permissions'] = '';
}
}
}
Thanks
After seeing your later comments, it looks as though you're wanting to save all permission data in a session variable so that you can look it up by permission ID:
$rows = $stmt->fetchAll();
foreach($rows as $row){
//Add to session, keyed by permission ID.
$_SESSION['user']['user_permissions'][$row['permission_id']] = $row;
}
//Then, if you want to see if said permission ID #21 exists:
if(isset($_SESSION['user']['user_permissions'][21])){
echo 'This user has permissions with ID 21!';
$permissionDetails = $_SESSION['user']['user_permissions'][21];
var_dump($permissionDetails);
}
Like any other "get it to work immediately" this question has contradicting conditions.
Like any other PHP code, it is ten times long than needed.
Like many other SO questions, it can be solved by quick manual lookup.
In case you need your permissions in array
public function getPermissions($user_role_id){
$sql = "SELECT permission_id FROM role_permission_tbl WHERE role_id = ?";
$stm = Database::get_database()->prepare($sql);
return $stm->execute(array($user_role_id))->fetchAll(PDO::FETCH_COLUMN);
}
note that assigning variables inside functions is a very bad practice. So, better call it this way
$_SESSION['user']['user_permissions'] = $user->getPermissions($user_role_id);
isset() is useless in conjunction with empty() as latter covers the former.
both isset() and empty() are useless for the function variable too, as it is always set by design
a verification for this particular input variable can be done, but for the sanely designed application it would be unnecessary.
setting a variable you are going to test with in_array() to an empty string will produce an error.
there is no use for the alias with single table.
PDO methods can be called dramatically shorter way, there is no use for stretching one simple query call to a whole screen of code.
echoing a system error message to a site user is an awful practice.
the very manual page for the fetchAll() contains an exact example for this very question of getting single column out of the query result.
there is no use for testing returned value explicitly, as it already contains either result or empty value (and luckily, fetchAll() will return even empty value of desired type).
Can you try $row = $stmt-> fetch(); instead of $row = $stmt->fetchAll(); if it is fetch only one record from table,
$row["permission_id"];

PHP OOP with mySQLi fetch

I am relatively new to PHP OOP and i know that there are numerous questions here on SO, but none of them seam to be pointing me in the right direction. I have created the class user, and I am calling this in another file.
I am trying to get the method 'reset' to call up 'connect', connect to the mysql db and then query it and set various properties to the row contents.
I am receiving no errors but for some reason it is not feeding the properties any data from the database.
I have tried placing the mySQL connect in the reset method, just to see if the variables cannot be passed between methods. But still no joy.
Can anyone point me in the right direction?
class user(){
public function reset(){
$this->connect();
$sql ='SELECT * FROM users WHERE user_id="'.$user_id.'"' ;
$result = mysqli_query($con,$sql);
while($row = mysqli_fetch_array($result))
{
$this->user_name=$row['dtype'];
$this->user_id=$row['user_id'];
$this->atype=$row['atype'];
$this->user_email=$row['user_email'];
$this->group1=$row['group1'];
$this->group2=$row['group2'];
$this->group3=$row['group3'];
$this->group4=$row['group4'];
$this->group5=$row['group5'];
$this->group6=$row['group6'];
}
// Test that these properties are actually being echoed on initial file... it is
// $this->user_name = "john";
// $this->user_email = "john#gmail.com";
// $this->dtype = "d";
// $this->atype = "f";
}
public function connect(){
//GLOBALS DEFINED IN INDEX.PHP
if ($db_open !== true){
$con=mysqli_connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
// Check connection
if (mysqli_connect_errno())
{
$debug_system .= 'Error on user.php: ' . mysqli_connect_error().'<br\/>';
} else {
$db_open = true;
$debug_system .= 'user.php: user details grab successful. <br\/>';
}
}
}
}
If you are relatively new to PHP OOP, it is strongly recommended not to mess with awful mysqli API but learn quite sensible PDO first, and only then, making yourself familiar with either OOP and prepared statements, you may turn to mysqli.
Nevertheless, there shouldn't be no function connect() in the class user. You have to have a distinct db handling class, which instance have to be passed in constructor of user class
The problem lies in this line:
$sql ='SELECT * FROM users WHERE user_id="'.$user_id.'"' ;
At no point do you actually define $user_id. Presumably you actually mean $this->user_id.
$sql ='SELECT * FROM users WHERE user_id="'.$this->user_id.'"' ;
Better still would be to make full use of parameterized queries, which might look like this:
$sql ='SELECT * FROM users WHERE user_id=?' ;
You would then prepare the statement and bind the user ID, then execute the query:
$stmt = mysqli_prepare($sql);
mysqli_stmt_bind_param($stmt, $this->user_id);
mysqli_stmt_execute($stmt);
And then fetch the results:
while($row = mysqli_stmt_fetch($result))
As you can see, there is a whole load more to modern MySQL libraries. I'd advise you to do more research into how MySQLi and parameterized queries work (and perhaps PDO as well: it's a superior library) before you use them further. It will be worth the effort.

Categories