Retrieving list of items using php - php

I am trying to retrieve a list of items from a mySQL db and insert them as a list in a select object on a webpage. The following is the bit of code that isnt working.
In the first line, I am trying to retrieve a JSON object from a public function called getBrands() in a singleton object I have created called DatabaseInterface.
The second line is then attempting to turn that JSON object into a php array.
Finally, I am running a loop which can option each item in between tags for the webpage.
Where am I going wrong?
<?php
var $brandArrayJSON = DatabaseInterface::getBrands();
$brandArray = JSON_decode($brandArrayJSON);
for ($loop=0; $loop < sizeof($brandArray); $loop++) {
echo "<option>$brandArray[$loop]</option>";
}
?>
EDIT: In case it helps, here is my DatabaseInterface singleton. I have included this file at the top of my php file
class databaseInterface {
private static $_instance;
// Private constructor prevents instantiation
private function __construct() {
}
public static function getInstance() {
if (!self::$_instance) {
self::$_instance = mysqli_connect(self::databaseHost, self::databaseUsername, self::databasePassword, self::databaseName);
if (mysqli_connect_errno(self::$_instance)) {
throw new Exception("Failed to connect to MySQL:" . mysqli_connect_error());
}
}
return self::$_instance;
}
public function getBrands() {
try {
$con = DatabaseInterface::getInstance();
} catch (Exception $e) {
// Handle exception
echo $e->getMessage();
}
$query = "SELECT psBrandName from brands";
$result = mysqli_query($con, $query) or die ("Couldn't execute query. ".mysqli_error($con));
$resultArray[] = array();
while ($row = mysqli_fetch_assoc($result)) {
extract($row);
$resultArray[] = $psBrandName;
}
return json_Encode($resultArray);
}

There is nothing "wrong" with the code, in that it should work (provided nothing is broken on the query-side). However, there are several things that should be improved.
First, basically what the getBrands() method is doing is equivalent to this:
$brandArray = json_encode(array('test','test2','test3'));
echo $brandArray; // returns ["test","test2","test3"]
Now, when you decode that you get the same thing you originally put in (an array):
$brandArray = json_decode('["test","test2","test3"]');
var_dump($brandArray); // Will dump an array
Since this is an array (not a PHP object), you can just use a foreach.
foreach($brandArray as $option) {
echo '<option>', $option, '</option>';
}
If you're worried about it being an object in some instances (maybe you had a non-array JS object which would be mostly the equivalent to a PHP associative array), you could cast the json_decode result into an array.
$brandArray = (array)$brandArray;
Now, in your getBrands() method, I would highly recommend just using $row['psBrandName'] instead of cluttering things up with extract, unless you have a really good reason to do this.

Related

Efficient way to reuse the same call to the same sql table

So I search for this title hoping someone would have already answered it however, I came across similar topics on other languages but not PHP so maybe this will help others.
I am constantly using this following script to call on the database but how can I create it so that I can make it just once at the top of the class for example and use it in every method on the class page that needs it. Example: An single page may not have all of the data it needs from the same table but if the table contains 50% of the data or more for that page, how can I modify this so that I can just say it once and let the rest of the following scripts display the data it extracted in the first place by calling it all just once?
Here's what I have now.
<?php
if($res = $dbConn->query("SELECT Column FROM Table")){
while($d = $res->fetch_assoc()){
printf("Enter HTML here with proper %s", $d['Column']);
}
}
?>
I want to call on this without the printf(" "); collect and store the data so that I can then call the results while printing or echoing the results with the HTML in other methods. What os the most efficient way? I don't want to make the same call over and over and over... well, you get the point.
Should I use fetch_array or can I still do it with fetch_assoc?
not very sure if it's the answer you want.
you can use include/include_once/require/require_once at the top of the page you want to use the function
for example:
general_function.php:
-----
function generate_form( $dbConn, $sql ) {
if($res = $dbConn->query("SELECT Column FROM Table")) {
while($d = $res->fetch_assoc()) {
printf("Enter HTML here with proper %s", $d['Column']);
}
}
}
and for those pages you want to use the function, just put
include "$PATH/general_function.php";
and call generate_form
Try this:
class QueryStorage {
public static $dbConn = null;
public static $results = [];
public static function setConnection($dbConn) {
self::$dbConn = $dbConn;
}
public static function query($query, $cache = true) {
$result = (array_key_exists($query, self::$results))?
self::$results[$query] : self::$dbConn->query($query);
if($cache) {
self::$results[$query] = $result;
}
return $result;
}
public static function delete($query) {
unset(self::$results[$query]);
}
public function clean() {
self::$results = [];
}
}
usage:
at top somewhere pass connection to class:
QueryStorage::setConnection($dbConn);
query and store it:
$result = QueryStorage::query("SELECT Column FROM Table", true);
if($result){
while($d = $result->fetch_assoc()){
printf("Enter HTML here with proper %s", $d['Column']);
}
}
reuse it everywhere:
$result = QueryStorage::query("SELECT Column FROM Table", true); // it will return same result without querying db second time
Remember: it's runtime cache and will not store result for second script run. for this purposes You can modify current class to make it
work with memcache, redis, apc and etc.
If I understood you correctly, then the trick is to make an associative array and access with its 'key' down the code.
$dataArray = array();
// Add extra column in select query for maintaining uniqness. 'id' or it can be any unique value like username.
if($res = $dbConn->query("SELECT Column,id FROM Table")){
while($d = $res->fetch_assoc()){
$dataArray[$d['id']] = $d['Column'];
}
}
//you have value in the array use like this:
echo $dataArray['requireValueId'];
//or , use 'for-loop' if you want to echo all the values
You need a function which takes in the query as a parameter and returns the result.
Like this:
public function generate_query($sql) {
if($res = $dbConn->query($sql)){
while($d = $res->fetch_assoc()){
printf("Enter HTML here with proper %s", $d['Column']);
}
}
}

MySQL close timing

I write a class to load data and export as SMARTY format through MySQLi
public function myRow($sql)
{
$this->connect();
$rec = $this->conn->query($sql);
$this->recordCount = $rec->num_rows;
if ($this->makeRecordCount) {
$this->totalRecordCount = $this->recordCount;
}
if ($this->recordCount > 0) {
$names = array();
$result = array();
$temp = array();
$count = $rec->field_count;
// Get fields name
while ($fields = mysqli_fetch_field($rec)) {
$names[] = $fields->name;
}
while ($row = $rec->fetch_assoc()) {
foreach ($names as $name) {
$temp[$name] = $row[$name];
}
array_push($result, $temp);
}
} else {
$result = null;
}
$this->conn->close();
return $result;
}
Then I can to something like
$sql = "SELECT * FROM `table`";
$datas = $class->myRow($sql);
$smarty->assign('datas', $datas);
There are maybe many data need to be loaded in one page, and I only want to connect to database once, but I want to do it all in class, I don't want to do something like
$class->connect();
$sql = "SELECT * FROM `table`";
$datas = $class->myRow($sql);
$smarty->assign('datas', $datas);
$sql = "SELECT * FROM `table2`";
$datas = $class->myRow($sql);
$smarty->assign('data2s', $data2s);
$class->close();
I feel it's ugly, but if I do this in class, that means I open and close connection when each data is loading, how to do it more beautiful?
maybe i'm wrong but you don't need to force a mysql connection to close because of the fact that if the connection is not persistent the php garbage collector close all connections after the script execution.
so i suggest you not to force the mysql close, let the garbage collector handle this task and only close the connection by yourself if you're sure that no more mysql transactions are required.
You simply don't need to (and shouldn't) open/close the connection inside your myRow() function.
Option 1 (naive approach): handle the connection at class level
class MyDAOClass {
private static $connection = null;
public function __construct() {
if (self::$connection === null) {
// establish connection here
}
}
public function myRow(...) {
// use self::$connection here
}
}
Option 2:
Handle the connection from outside the class altogether (possibly in a singleton class), since all objects from your application probably can share the same object.
Your second suggestion is what I would do.
$class->connect();
$sql = "SELECT * FROM `table`";
$datas = $class->myRow($sql);
$smarty->assign('datas', $datas);
$sql = "SELECT * FROM `table2`";
$datas = $class->myRow($sql);
$smarty->assign('data2s', $data2s);
$class->close();
You connect to the database once. As PHP is single threaded, you will load the first result, then go right away and load the second result. Once everything is done, you close the connection. No connection is kept alive longer than it has to, which is good.
What I usually do it make a method associated with Smarty that closes my database-connection too. That way I don't have to worry about closing it.
Something like this:
<?php
// Store reference to Smarty in Class
$class->setSmarty($smarty);
[...]
// Done with all database fetching, now display the template
$class->display('my_template.tpl');
[...]
// Example inplementation of the class
Class YourClass {
private $smarty;
public function setSmarty($smarty) {
$this->smarty = &$smarty;
}
public function display($tpl) {
$this->close();
$this->smarty->display($tpl);
}
}
?>

The lifecycle of an object in PHP

I have two PHP scripts that I included below. Both of them attempt to do the same thing, but one works and one does not. I'm looking for someone to explain what PHP is doing under the covers. I'm new to PHP and I suspect that my Java experience is poisoning my thought process when I work in PHP.
What I'm attempting to do is functionally very simple -- Insert a question into a mySQL database table, retrieve the primary key of the inserted row, and then insert five answers into another table with a foreign key relationship to the question.
My original logic looked like this:
ManageQuestions.php:
<?php
session_start();
include('query.php');
echo "begin <br>";
if (isset($_POST['submit'])) {
echo "manageQuestion <br>";
$query = new Query;
$query->createTransaction();
$query->executeCreateUpdateDelete("INSERT INTO question (question) VALUES ('".$_POST['question']."'); ");
$question_pid = $query->getLastInsertedId();
$query->commitTransaction(); // Need to figure out how to do dirty reads so I can remove this.
echo $question_pid."<br>";
$result = $query->executeRead("SELECT question_pid FROM question where question_pid = '".$question_pid."';");
echo count($result)."<br>";
//if (count($result) === 1) {
$query->createTransaction(); // Need to figure out how to do dirty reads so I can remove this.
foreach($_POST['answer'] as $answer) {
$correctAnswers = 0;
$query->executeCreateUpdateDelete("INSERT INTO answer (question_fid, answer, isCorrect) VALUES ('".$question_pid."','".$answer['answer']."','".$answer['isCorrect']."')");
if ($answer['isCorrect'] === 1) {
$correctAnswers = $correctAnaswers + 1;
if ($correctAnswers > 1){
echo "Failed to insert answers";
$query->rollBackTransaction();
break;
}
}
}
echo "Success";
$query->commitTransaction();
/* } else {
echo "Failed to insert question";
$query->rollBackTransaction();
} */
}
?>
Query.php:
<?php
session_start();
class Query
{
private $host="<censored>";
private $username="<censored>";
private $password="<censored>";
private $db_name="<censored>";
private $pdo;
private $pdo_statement;
private $pdo_exception;
public function executeCreateUpdateDelete($pQuery)
{
$this->pdo_statement = $this->pdo->prepare($pQuery);
return $this->pdo_statement->execute();
}
public function executeRead($pQuery)
{
try
{
$dbh = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
$result = $dbh->query($pQuery);
$dbh = null;
return $result->fetchAll();
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
public function createTransaction()
{
$this->pdo = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
$this->pdo->beginTransaction();
}
public function commitTransaction()
{
$this->pdo->commit();
}
public function rollBackTransaction()
{
$this->pdo->rollBack();
}
public function getLastInsertedId()
{
$this->pdo->lastInsertId();
}
}
?>
When I rewrote my logic to not use a separate query class, I was able to do what I wanted to do. The only thing I've been able to find online about the life cycle of a PHP object is that it begins at the start of a script and ends at the end of a script. Does that imply that my query object is instantiated every time I call one of its methods and garbage collected when that particular method ends? Moving the logic out of that class and into the script caused my logic to work. This is what it looks like now:
ManageQuestions.php:
<?php
session_start();
include('query.php');
echo "Begin <br>";
if (isset($_POST['submit'])) {
echo "manageQuestion <br>";
$host="<censored>";
$username="<censored>";
$password="<censored>";
$db_name="<censored>";
$pdo = new PDO("mysql:host=$host;dbname=$db_name", $username, $password);
$stmt = $pdo->prepare("INSERT INTO question (question) VALUES ('".$_POST['question']."'); ");
$stmt->execute();
$question_pid = $pdo->lastInsertId();
echo $question_pid."<br>";
$stmt = $pdo->query("SELECT question_pid FROM question where question_pid = '".$question_pid."';");
$result = $stmt->fetchAll();
echo count($result)."<br>";
foreach($_POST['answer'] as $answer) {
$correctAnswers = 0;
$stmt = $pdo->prepare("INSERT INTO answer (question_fid, answer, isCorrect) VALUES ('".$question_pid."','".$answer['answer']."','".$answer['isCorrect']."')");
$stmt->execute();
}
echo "Success";
}
?>
Even though this fixed my issue, I don't understand why. If someone could explain that, I would be extremely grateful.
Cheers!
Does that imply that my query object is instantiated every time I call one of its methods and garbage collected when that particular method ends?
No. It's per request, not per method call. So the query object is instantiated every time the script is called and it gets unset (and not necessarily garbage collected) when the script ends.
However you could better manage the resource of the PDO object inside your Query class because you create a new instance (which would mean that it connects again to the database server which is not that cheap). So some lazy loading does not seem bad:
class Query
{
...
/** #var PDO */
private $pdo;
...
private function getPdo() {
if (!$this->pdo) {
$this->pdo = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
}
return $this->pdo;
}
public function executeRead($pQuery)
{
try {
$dbh = $this->getPdo();
$result = $dbh->query($pQuery);
return $result->fetchAll();
} catch (PDOException $e) {
echo $e->getMessage();
}
}
public function createTransaction()
{
$this->getPdo()->beginTransaction();
}
...

PHP/MySQL isolating database access in a class - how to handle multiple row result set in an OOP manner

PHP/MySQLisolating database access in class - how to handle multiple row Selects
Here’s a coding question.
I isolated all DB access functions in a class
<?php
class DB {
var $conn;
function DBClass () {
#$this-> conn = mysqli_connect (DB_SERVER, DB_USER, DB_PASS, DB_NAME);
}
function validateUser ($aUserid, $aPassword) {
… validation code – sql injection code etc..
$sql = "Select userid, name, level From users where userid = '$aUserid' and password = '$aPassword'";
$result = mysqli_query ( $this->conn, $sql );
if (!$result || (mysqli_num_rows ($result) < 1)) {
return false;
}
$dbarray = mysqli_fetch_assoc ($result); // get a row
return $dbarray;
}
function getProduct ($aProductid) {
return $dbarray;
}
function getProductList () {
// <----------- this would be the problem function
}
}
$DB = new DBClass();
?>
My calling routine:
<?php
$dbarray = $DB->validateUser ($_POST['userid'], $_POST['password']);
?>
No problem it works fine. I run into a problem with a result set of more than one row. Now I have to get back to the class object for each row. It’s no problem if I include the MySQL code in the calling routine, but I’d like to keep it isolated in my class and I’m not sure how to code it.
Any thoughts? Any examples?
If you use PHP 5.3.0 and mysqlnd, you can use the new function mysqli_fetch_all(). This returns an array of associative arrays.
If you use an earlier version of PHP, you could switch to using PDO, and use the function PDOStatement::fetchAll().
You ask in a comment what about a very large result set. It's true that an unbounded result set could cause the array to exceed your PHP memory limit and that would cause a fatal error and halt the script. But is this really a problem? How many products do you have? You could use LIMIT to make sure the query isn't unbounded.
Re the other part of your questions regarding going back to a class, I'd suggest making an Iterator class:
class DB implements IteratorAggregate
{
protected $_data = array();
public function getProductList() {
// fetch all results from SQL query, stuff them into $this->_data
return $this->getIterator();
}
public function getIterator() {
return new ArrayIterator($this->_data);
}
}
Now you can use the class in a foreach loop:
$db = new DB();
foreach ($db->getProductList() as $product) {
// do something with each product
}
The IteratorAggregate interface means you can even do this:
$db = new DB();
$db->getProductList();
// ...other steps...
foreach ($db as $product) {
// do something with each product
}
Of course you could only store one result set at a time with this method. If you used your DB class for any other queries in the meantime, it would complicate things. For this reason, most people don't try to write a single class to encapsulate all database operations. They write individual classes for each type of Domain Model they need to work with, decoupled from the database connection.
you could save the result in an array and return it:
function getProductList () {
$sql = "SELECT ...";
$result = mysqli_query ( $this->conn, $sql );
$myProducts = array();
while ($row = mysqli_fetch_assoc($result))
$myProducts[] = $row; // or array_push($myProducts, $row)
}
return $myProducts
}
As a result you'll have an array of arrays and each element of it will contain one row of the result.
You have a SQL injection right in your login page.
What happens if someone inputs that as password:
xxx' OR 'yyy' <> 'x

How do I loop through a MySQL query via PDO in PHP?

I'm slowly moving all of my LAMP websites from mysql_ functions to PDO functions and I've hit my first brick wall. I don't know how to loop through results with a parameter. I am fine with the following:
foreach ($database->query("SELECT * FROM widgets") as $results)
{
echo $results["widget_name"];
}
However if I want to do something like this:
foreach ($database->query("SELECT * FROM widgets WHERE something='something else'") as $results)
{
echo $results["widget_name"];
}
Obviously the 'something else' will be dynamic.
Here is an example for using PDO to connect to a DB, to tell it to throw Exceptions instead of php errors (will help with your debugging), and using parameterised statements instead of substituting dynamic values into the query yourself (highly recommended):
// connect to PDO
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "password");
// the following tells PDO we want it to throw Exceptions for every error.
// this is far more useful than the default mode of throwing php errors
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepare the statement. the placeholders allow PDO to handle substituting
// the values, which also prevents SQL injection
$stmt = $pdo->prepare("SELECT * FROM product WHERE productTypeId=:productTypeId AND brand=:brand");
// bind the parameters
$stmt->bindValue(":productTypeId", 6);
$stmt->bindValue(":brand", "Slurm");
// initialise an array for the results
$products = array();
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$products[] = $row;
}
According to the PHP documentation is says you should be able to to do the following:
$sql = "SELECT * FROM widgets WHERE something='something else'";
foreach ($database->query($sql) as $row) {
echo $row["widget_name"];
}
If you like the foreach syntax, you can use the following class:
// Wrap a PDOStatement to iterate through all result rows. Uses a
// local cache to allow rewinding.
class PDOStatementIterator implements Iterator
{
public
$stmt,
$cache,
$next;
public function __construct($stmt)
{
$this->cache = array();
$this->stmt = $stmt;
}
public function rewind()
{
reset($this->cache);
$this->next();
}
public function valid()
{
return (FALSE !== $this->next);
}
public function current()
{
return $this->next[1];
}
public function key()
{
return $this->next[0];
}
public function next()
{
// Try to get the next element in our data cache.
$this->next = each($this->cache);
// Past the end of the data cache
if (FALSE === $this->next)
{
// Fetch the next row of data
$row = $this->stmt->fetch(PDO::FETCH_ASSOC);
// Fetch successful
if ($row)
{
// Add row to data cache
$this->cache[] = $row;
}
$this->next = each($this->cache);
}
}
}
Then to use it:
foreach(new PDOStatementIterator($stmt) as $col => $val)
{
...
}

Categories