I have a standardized sequence of code which I used to display topic information on the home page and other pages on my site. I want to throw it in an include file so that I don't have to keep fixing multiple pages. The problem is sometimes this include occurs in a while statement which means there was a previous query supplying information for sorting purposes.
When the code is raw in the while statement, it works as it should and if there are multiple ids being served to the code from the previous query, it shows multiple results. However, if this code is in an include, I will only see one result. I assume because the include file only executes once. How would I serve an include file as the equivalent as my raw code?
Include
//outside query
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$topic_id=htmlspecialchars( $row['topic_id'], ENT_NOQUOTES, 'UTF-8' );
//code to display topics
include('display_topics.php');
}
Raw Code
//outside query
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
//code to display topics
$sql = "SELECT * FROM topic WHERE id=?";
$stmt = $conn->prepare($sql);
$stmt->bindValue(1,topic_id, PDO::PARAM_INT);
$result=$stmt->execute();
}
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
//yada yada
...
}
Don't do it this way.
It's much better to do one include, and to declare a function in it that does what you need:
function display_topics($topic_id)
{
....
}
Call that function inside the loop, and pass all necessary data to it.
Include the file as normal, but put the repeated code in a function. Then, where you wish to add the code simply call the function.
That word, I don't think it is for what you think it is for.
Generally, include's use should not be used that way. That's why God invented functions (or Ada Byron, if you're not theologically inclined).
Try this instead:
function execute_row($row, $conn)
{
$topic_id=htmlspecialchars( $row['topic_id'], ENT_NOQUOTES, 'UTF-8' );
$sql = "SELECT * FROM topic WHERE id=?";
$stmt = $conn->prepare($sql);
$stmt->bindValue(1,topic_id, PDO::PARAM_INT);
return $stmt->execute();
}
Then, in your while statement:
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$result = execute_row($row, $conn);
}
TADA! And the best part is, it makes your code smaller, easier to read, and faster to parse.
Related
My question is that I use mysqli in class function. I want to be able to return $stmt and use it, so that I can separate a lot of php from my html.
Here is my first bit of code, which is in the class of ticket
public function listTickets(){
$query = "SELECT `subject` FROM `tickets` WHERE `test_id`=?";
$stmt = $this->db->prepare($query);
$stmt->bind_param('i',$_SESSION['data']);
$stmt->execute();
$stmt->bind_result($subject);
return $stmt;
}
Then I call it like this from another file, but of course this does not work, because for some reason my class function is not returning a binded $stmt. However there is no error.
$stmt=$ticket->listTickets();
while($stmt->fetch())
{
echo '<pre>'.$subject.'</pre>';
}
However if I bind it after returning it works, which is annoying because I have already binded it in my function.
$stmt=$ticket->listTickets();
$stmt->bind_result($subject);
while($stmt->fetch())
{
echo '<pre>'.$subject.'</pre>';
}
So binding after returning works, but I would rather returned the binded $stmt so I can have less code cluttering up my html.
I know there are various ways of returning output from a mysqli call like loading it into arrays and stuff, but I was trying to do it with as less code as possible (and please nobody suggest pdo.)
So my question is how do I return a binded $stmt from my function without having to bind it after returning?
Ok going to add a little more. My mysqli is working correctly as when I do this inside the function it works ok
while($stmt->fetch())
{
echo '<pre>'.$subject.'</pre>';
}
$subject is not defined in the listTickets() method. Variables inside the method scope is not visible outside of the method. I think the last code you wrote is the best approach.
Seeing as nobody could give me a satisfactory answer I painstakenly found my own answer. It was nothing to do with scope.
Actually I have two answers and they both work. In the new answer I don't have to bind my variables, because I am using either fetch_assoc, or fetch_object.
So here is my answer
public function listTickets(){
$query = "SELECT `subject` FROM `tickets` WHERE `test_id`=?";
$stmt = $this->db->prepare($query);
$stmt->bind_param('i',$_SESSION['data']);
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();
return $result;
//Notice I am not binding at all, and instead of returning $stmt, I am returning $result.
}
Ok the code above is the same for both answers, but in my other file I can do it two different ways.
Here is the first way, which outputs an object
$result=$ticket->listTickets();
while($row = $result->fetch_object()){
echo $row->subject;
}
And here is the second way, which outputs an associative array
$result=$ticket->listTickets();
while($row = $result->fetch_assoc()){
echo $row['subject'];
}
The difference is that the first one uses an object and the second one uses an associative array.
It took me many hours to work this out, but I am happy I actually worked it out on my own.
I am using PDO to access my data base and am looping using two while loops with fetch at the same time, seen below:
$DBH = new PDO('mysql:host=localhost;dbname=database;charset=utf8',$dblogin,$dbpass);
$sql = 'SELECT * FROM table';
$STH = $DBH->prepare($sql);
$STH->execute();
while ($bm_table = $STH->fetch(PDO::FETCH_ASSOC))
{
// SQL Query
$sql1 = 'QUERY HERE';
$STH1 = $DBH->prepare($sql1);
$STH1->execute();
// Loops through using different handle, but what if I used STH again?
while ($row = $STH1->fetch(PDO::FETCH_ASSOC))
{
SomeFunction($bm_table,$row);
}
}
As you can see above I am using a different statement handle ($STH, $STH1 etc.) Is this necessary? Or can I use just one statement handle for everything. The reason I have used multiple handles is as the $bm_table value that uses $STH, will still be in use while I am fetching $row wouldn't that change the value of $bm_table or stop the fetch from working? How does the handles with PDO work? Especially when in this case I have two simultaneous fetch loops running at the same time using the same PDO connection.
So the main thing I am looking for here is if I have two statements that are running simultaneously is it important that I use different handles when I continue to use the same connection?
$STH and STH1 are not statement handles, they're just PHP variables. You can reassign a variable if you no longer need its old value. But in the case of this code, you still need the old value.
If you assign $STH inside the outer loop to the handle returned by the second prepare() call, then when it gets back to the top of the loop and re-executes the $STH->fetch() test, it will try to fetch from the second query, not the first one. This will immediately end the outer loop because all those rows have been read.
You can reuse a statement handle for repetitions of the same query. This is very useful when the query has parameters:
$stmt = $DBH->prepare("SELECT * FROM tablename WHERE id = :id");
$stmt->bindParam(':id', $id);
foreach ($id_array as $id) {
$stmt->execute();
$row = $stmt->fetch();
// do stuff with $row
}
If I understand you correctly what you want is dynamic query?... just put a parameter on your method then...
something like this. call it as much as you want with difference parameters though.
Class SampleClass{
public function GetAll($tablename)
{
$sth = $this->prepare("SELECT * FROM $tablename");
$sth->execute();
return $sth->fetchAll();
}
}
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"];
I'm currently trying to create a function where I can control what field and what values get pulled. This is something I had in mind, but it doesn't work. I get no error, it returns an empty array.
public function test ($field, $id) {
$sql = $this->con->prepare("SELECT ? FROM Content WHERE id=?");
$sql->bindParam(1, $field);
$sql->bindParam(2, $id);
$sql->execute();
while ($row = $sql->fetch()) {
echo $row;
}
}
I'm unsure about the "SELECT ?..." part I'm not 100% sure that is the correct way. The basic idea is I can make a call anywhere like:
< ?php $obj = new handler; $obj->test($_GET['Title'], $_GET['id']); ?> which will echo the Title with the correct id.
the way prepared statements work is that the quesry is prepared and then the data for the fields is sent. Because the first '?' refers to an actual part of query it can not be prepared.
Workarounds:
a) Fetch the whole row and return just the field you need
$this->con->prepare("SELECT * FROM Content WHERE id=?");
//.......
return $row->$field;
b) Insert the field raw into the query (you can use quotes though)
$this->con->prepare("SELECT `{$field}` FROM Content WHERE id=?");
Also if you intend to use it like the way you described it is possible that you be making a whole lot of dduplicate calls to the database
I'm trying my hand at custom functions in PHP in order to streamline a lot of stuff I'm otherwise doing manually. I'm damn new to custom functions so I'm not sure the limitations. Right now I'm trying to get data with MySQLi using custom functions Here's the code, and then I'll explain the issue:
function connect_db($db = 'db_username') {
iconv_set_encoding("internal_encoding", "UTF-8");
mb_language('uni');
mb_internal_encoding('UTF-8');
# $mysqli = new mysqli('host',$db,'password',$db);
if(mysqli_connect_errno())
{
die('connection error');
}
}
This one seems to be working fine. It's the next function I'm having more trouble with.
edit: Updated thanks to Jeremy1026's response
function do_query($db = 'default_db', $query) {
connect_db();
$result = $mysqli->query($query);
if(!$result){
trigger_error("data selection error");
}
while($row = $result->fetch_assoc()){
$result_array[] = $row;
}
return $result_array;
}
My host forces database names and usernames as the same, so if the db name is 'bob' the username to access it will be 'bob' as well, so that's why $db shows up twice in the connection.
The problem I'm having is that these two functions are in functions.php and being called from another page. I want to be able to pull the results from the query in that other page based on the column name. But I also need to be able to do this with formatting, so then maybe the while() loop has to happen on that page and not in a function? I want this to be as universal as possible, regardless of the page or the data, so that I can use these two functions for all connections and all queries of the three databases I'm running for the site.
God I hope I'm being clear.
Big thanks in advance for any suggestions. I've googled this a bit but it's tough to find anything that's not using obsolescent mysql_ prefixes or anything that's actually returning the data in a way that I can use.
Update: I'm now getting the following error when accessing the page in question:
Fatal error: Call to a member function query() on a non-object in /functions.php`
with the line in question being $result = $mysqli->query($query);. I assume that's because it thinks $query is undefined, but shouldn't it be getting the definition from being called in the page? This is that page's code:
$query = "SELECT * FROM `table`";
$myArray = do_query($db, $query);
echo $myArray['column_name'];
In your 2nd function you aren't returning any data, so it is getting lost. You need to tell it what to return, see below:
function do_query($db = 'default_db', $query) {
connect_db();
$result = $mysqli->query($query);
if(!$result){
trigger_error("data selection error");
}
while($row = $result->fetch_assoc()){
$result_array[] = $row;
}
return $result_array;
}
Then, when using the function you'll do something like:
$myArray = do_query($db, 'select column from table');
$myArray would then be populated with the results of your query.
This is a half-answer. The following single function works in place of the two.
function query_db($database, $new_query) {
$sqli = new mysqli('host', $database, 'password', $database);
$sqli->set_charset("utf8");
global $result;
if($result = $sqli->query($new_query)){
return $result;
}
}
By adding global $result I was able to access the results from the query, run from another page as
query_db("username","SELECT * FROM `column`");
while($row = $result->fetch_assoc()){
print_r($row);
}
It's more streamlined than I have without functions, but it's still not idea. If I have the connection to the database in another function, it doesn't work. If I try to put the while loop in the combined function, it doesn't work. Better than nothing, I guess.