I am try to make an PDO sql inside function but it doesn't work. got no response from it. it works when not using function. my purpose is to make my code small. anyone can shed a light. thanks.
function Test() {
$get_name = $smt->prepare("SELECT * FROM customer WHERE id = '1'");
$get_name->execute();
foreach ($get_name as $temp) {
$name = $temp['name'];
$address = $temp['address'];
$phone = $temp['phone'];
$page = $temp['page'];
}
eval("\$page = \"$page\";");
echo $page;
eval("\$page = \"$page\";");
echo $page;
}
Test();
I'd probably refactor your code to something like:
function getCustomerInfo(PDO $pdo, $customerId)
{
// use a prepared statement that can get you info on any customer
$statement = $pdo->prepare(
"SELECT * FROM customer WHERE id = :customerId LIMIT 1");
// get the result resource from the database
$result = $statement->execute(array(
':customerId' => $customerId
));
// fetch the first row in the result as an associative array
// and return it to the caller.
return $result->fetchFirst(PDO::FETCH_ASSOC);
}
// use your connection in place of $pdo
$customerData = getCustomerInfo($pdo, 1);
// now you can do stuff with your data
var_dump($customerData);
This is better because it does not rely on global state, functions should never-ever-ever do that. and it uses prepared, parameterized sql that makes it faster and the function more useful for customers other that the one where id=1.
You need to make the pdo instance global within the function
function Test() {
global $smt;
Related
I am working to create a content class which will pull all content from the database via a PDO, then run the results through a method which will convert the results into objects, and the loop through the objects, and echo the object to a specific module of the webpage.
What is expected
When the class is activated, there will be an instance created via a PDO that will retrieve the needed data from the mysql database. Then this information will echo out and display on the webpage.
What is happening
I end up with no errors and the boolean number "1" where content should be. At first I thought this was an sql error. I get the same result "1" if I use print_r($query_result). See my tests below.
My class code is below
<?php
class Content {
// --- START OF ACTIVE RECORD CODE ---
public $n_id;
public $n_name;
public $n_text;
public $n_photo;
// Instantiating a STATIC Database Connection for the class to use
static protected $dbconnect;
static public function database($dbconnect) {
self::$dbconnect = $dbconnect;
}
// constructing arguments
public function __construct($args=[]) {
$this->n_id = $args['n_id'] ?? '';
$this->n_name = $args['n_name'] ?? '';
$this->n_text = $args['n_text'] ?? '';
$this->n_photo = $args['n_photo'] ?? '';
}
// Multi use method to pass in sql that will execute the PDO only two parameters are bound ID and contentText.
static public function find_by_sql($sql) {
// -------------BEGIN PDO-----------
// preparing PDO by loading sql, calling db connection, and storing in variable $stmt
$stmt = self::$dbconnect->prepare($sql);
// Binding Parameters for sql
$stmt->bindParam(':nid', $n_id, PDO::PARAM_INT);
$stmt->bindParam(':nall', $n_name, PDO::PARAM_STR);
$stmt->bindParam(':ntext', $n_text, PDO::PARAM_STR);
$stmt->bindParam(':nphoto', $n_photo, PDO::PARAM_INT);
// executing $stmt PDO and storing the result in $stmt
$query_result = $stmt->execute();
return $query_result;
// clearing the PDO after information is stored in $record
$stmt->closeCursor();
// ------------END PDO ----------
// Checking to see if a result exist. If nop result is stored in $stmt, then it will echo "Database query failed."
if(!$query_result) {
exit("Query doesn't exist.");
}
// -------- BEGIN TURNING RESULTS INTO OBJECTS --------
$object_array = [];
// The result $stmt will be stored in the variable $record
while($record = $query_result->fetchAll()) {
// Taking $record and passing it to the static method instantiate() - see below. This method will return the $object_array.
$object_array[] = self::instantiate($record);
}
return $object_array;
// ------------ END TURNING RESULTS INTO OBJECTS --------
}
// method to test passing $sql to method find_all_sql();
static public function find_all(){
$sql = "SELECT * FROM nmain WHERE nid = :id AND nall = :nall AND ntext = :ntext AND nphoto = :nphoto";
return self::find_by_sql($sql);
}
// --- BEGIN INSTANTIATE METHOD TO CREATE OBJECTS ---
static protected function instantiate($record) {
$object = new self;
// Auto assign values
foreach($record as $property => $value) {
if(property_exists($object, $property)){
$object->$property = $value;
}
}
return $object;
}
// ----- END INSTANTIATE OF RECORD TO CREATE OBJECTS ---
// ---END OF ACTIVE RECORD CODE---
}
?>
**On my html webpage:**
$contents = Content::find_all();
foreach ((array) $contents as $content) {
echo $content;
}
What I have tested
This is the output I get when I run var_dump($stmt);
object(PDOStatement)#3 (1) { ["queryString"]=> string(119) "SELECT * FROM ndb WHERE id = :id AND nall = :nall AND ntext = :ntext AND nphoto = :nphoto" }
If I copy the query and paste it in myphpadmin the query will run binding the params.
This is the output if I run var_dump($query_result):
bool(true) if I use print_r($query_result) I get "1"
This passes my if(!$query_result) test
If I run var_dump($record) or var_dump($query_result) I get nothing. It seems as if $query_result, because it is a bool, has no array to pass to $record.Therefore, there is nothing to convert to an object.I am at a loss here. Is it my PDO binding?
Your fetch should be on the statement and not the result of the execute (which is just to say the execute has succeeded or failed), also fetchAll will attempt to return all records, what you most likely want is fetch to process 1 record at a time. So you should have something like...
while($record = $stmt->fetch()) {
You can now remove the earlier return which is stopping further processing.
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']);
}
}
}
Right now, I'd wrote a function in my model as:
public function getRowsByZipCode($zip)
{
// SQL to get all the rows with the given zip code
$stmt = $this -> getAdapter()
-> query( "SELECT *
FROM
table_name
WHERE
table_name.status = 1 AND
table_name.zip={$zip}");
$resultRows = $stmt->fetchAll();
// -------------------------------------------------------- //
// Convert result set to an array of objects
$resultObjects = array();
// If there is atleast one row found in DB
if(count($resultRows) > 0)
{
// Loop throguh all the rows in the resultset
foreach($resultRows as $resultRow) {
// Create table row and fill it with the details got from DB
$h = $this->createRow();
$h->setFromArray($resultRow);
// Add to the array
$resultObjects[] = $h;
}
}
return $resultObjects;
// -------------------------------------------------------- //
}
Which is working perfectly as I needed. And it is returning me an array that contains the tables row objects(App_Model_TableName Objects), which will be used later for further operations like save and delete etc.
What I really want is to remove the code that loop through the rows I got from the result set and converting each row to an object of App_Model_TableName that I'd wrote inside the comments // --- //.
Thanks in advance.
Firstly, I am assuming you are using PDO.
Try the following
class App_Model_TableName
{
public $status;
public $zip;
// public $other_column;
}
class YourClass
{
protected function getAdapter()
{
// Do adapter stuffs
}
public function query($query, array $param)
{
// When Using PDO always use prepare and execute when you pass in a variable
// This will help prevent SQL injection
$stmt = $this->getAdapter()->prepare($query);
return $query->execute($param);
}
/**
* #return App_Model_TableName[]
*/
public function getRowsByZipCode($zip)
{
// SQL to get all the rows with the given zip code
// This way will help prevent SQL injection
$query = "SELECT * FROM table_name WHERE table_name.status = 1 AND table_name.zip = :zip";
$qData = array(':zip' => $zip);
$results = $this->query($query, $qData);
return $results->fetchAll(PDO::FETCH_CLASS, 'App_Model_TableName');
}
}
Calling YourClass::getRowsByZipCode() will then return you an array of App_Model_TableName objects. You can then access them like:
$data = $instance_of_yourclass->getRowsByZipCode(12345);
foreach ($data as $row)
{
echo $row->zip;
echo $row->do_stuff();
}
All these awesome functions I found on:
http://php.net/manual/en/pdostatement.fetchall.php
http://php.net/manual/en/pdostatement.execute.php
Disclaimer: this code was not tested :(
Be cool but stay warm
Finally, I had found the solution:
public function getRowsByZipCode($zip)
{
// SQL to get all the rows with the given zip code
$stmt = $this -> getAdapter()
-> query( "SELECT *
FROM
table_name
WHERE
table_name.status = 1 AND
table_name.zip={$zip}");
$resultObjects= array();
while($data = $stmt->fetch())
{
$h = $this->createRow();
$h->setFromArray($data);
// Add to array
$resultObjects[] = $h;;
}
return $resultObjects;
}
I had removed the code that do the fetchAll() and loop through each row in the resultset. Now, I am taking each row from the resultset and creating an row of App_Model_TableName object using the data we got from the resultset.
Working perfectly for me.
I have tried a few different ways to make this work to no avail.
Basically, I have these 4 lines that are in many functions:
function getID($URL){
//These 3 plus this comment line
$parentQ = "select * from cdi_content where URL=\"$URL\"";
$parentResult = mysql_query($parentQ); // Run the Query
$link = mysql_fetch_assoc($parentResult); // Query Result
...continues...
That basically tells the database to check $URL and if it matches the URL string in the database, it grabs all of the data associated with that URL, and I grab what I need with
$link['ID'];
Which would give me the ID associated with the $URL URL.
The function checks a list of conditionals that either print the 'override' variable ($ID), the default variable ($defaultID) or pulls from the server ($link['ID']), like below. The 'override' is a variable outside of the function that is currently called in by global $ID.
$ID = ''; //Overrides if set
function parseData($URL){
//Initialize Query for Table Data
$parentQ = "select * from cdi_content where URL=\"$URL\"";
$parentResult = mysql_query($parentQ); // Run the Query
return mysql_fetch_assoc($parentResult); // Query Result
};
function getID($URL){
global $ID;
$serverID = parseData($URL);
if(empty($ID)){
if(empty($serverID)){
echo $defaultID;
} else { echo $serverID['ID']; }
}//end of ifs
else
{ echo $ID; }
};
So you you want to parse the data row you would need search criteria $criterion and a field you you want it to return:
function getField($criterion, $returnField){
$parentQ = "select * from cdi_content where URL='".$criterion."' LIMIT 1"; // also make sure you that $criterion is safe to use in a query
$parentResult = mysql_query($parentQ); // Run the Query
if ($parentResult)
{
$row = mysql_fetch_assoc($parentResult);
return $row[$returnField];
}
else
{
return FALSE;
}
}
Now you can call it:
$linkId = getField($url, 'ID');
If I'm understanding you correctly, you're just trying to refactor that function so you don't have to keep on re-writing it. Is that correct?
If so, you can extract a new function like this:
function getLink($URL){
$parentQ = "select * from cdi_content where URL=\"$URL\"";
$parentResult = mysql_query($parentQ); // Run the Query
return mysql_fetch_assoc($parentResult);
}
And then call it like this:
function getID($URL){
$link = getLink($URL);
}
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