I have a method called getField and it calls fetch, and I was wondering if there is method similar to fetch, only that it doesn't move the internal cursor forward, and instead stays where it is.
So, I have the following methods:
public function getField($field_name){
if(!is_array($this->row) || empty($this->row)){
$this->row = $this->stmt->fetch(PDO::FETCH_ASSOC);
}
return $this->row[$field_name];
}
public function nextRow($type = PDO::FETCH_ASSOC){
if(!($this->stmt instanceof PDOStatement)){
return array();
}
$this->row = $this->stmt->fetch($type);
$this->setArray($this->row);
return $this->row;
}
When I call getFields then nextRow the cursor moves ahead before nextRow is called. When that happens I would like the cursor to stay where it is and only increment when nextRow is called. Is there something like this?
Example
$this->db->query($somequery, $arrary_replacements);
if($this->db->getField("myField") === null){
// Do some stuff
// Do some database queries too
}else{
$row = $this->db->nextRow();
// Process $row
}
Your example
$this->db->query($somequery, $arrary_replacements);
if($this->db->getField("myField") === null){
// Do some stuff
// Do some database queries too
}else{
$row = $this->db->nextRow();
// Process $row
}
In my mind, your example usage is flawed. You have already accessed the first row by using getField(), therefore logically, I would assume nextRow() should get the second row. Otherwise you are saying that nextRow should return the current row but continue to the next row, which through my eyes, is confusing.
If you actually want the $row for processing then why don't you do this?
$this->db->query($somequery, $arrary_replacements);
$row = $this->db->nextRow();
if($row['myField'] === null){
// Do some stuff
// Do some database queries too
}else{
// Process $row
}
Otherwise, I think you should consider adding a new function named getRow() or currentRow() to obtain the current row data (return $this->row) as to not confuse other developers.
Related
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']);
}
}
}
I would like to do these actions step by step:
first DB update
copy file
unlink file
second DB update
It is working, but I don't know if my code is correct/valid:
$update1 = $DB->query("UPDATE...");
if ($update1)
{
if (copy("..."))
{
if (unlink("..."))
{
$update2 = $DB->query("UPDATE ...");
}
}
}
Is it possible to use if statement this way?
I found that it is usually used with PHP operators and PHP MySQL select, for example:
$select = $DB->row("SELECT number...");
if ($select->number == 2) {
...
}
Sure, your ifs work fine. What would look and flow better would be using a function like this:
function processThings() {
// make sure anything you use in here is either passed in or global
if(!$update1)
return false;
if(!$copy)
return false;
if(!$unlink)
return false;
if(!$update2)
return false;
// you made it!
return true;
}
make sure you call $DB as a global variable, plus pass in whatever strings you need etc etc
I have a somewhat general question regarding what's best when programming in PHP using also database connections. I am building a project which includes several modules and each module needs to connect to the MySQL sometimes. The module files are included in the main index.php depending on the action selected from the menu by the user. I guess, most projects work this way anyway.
So far what I do is always open the connection at the start of each module file and close it after the queries have run.
My question is this: is it better to open the connection to the database in the beginning of the index.php and close it in the end so to have 1 connection open, or do multiple connections which stay open for less time? What's best for speed and overhead?
As N.B. pointed out, you should probably setup a class to handle all your database related tasks. I am posting a snippet from my code archives to illustrate how you can setup such a class. This is solely for purposes of illustrating and not guaranteed to work for you if you just copy and paste. It may need some refinement. It also makes use of the smarty class to process data views.
I recommend stripping out whatever you don't need. Set your MySQL connection params. In your index file, you can instantiate a SQL object and simply call the appropriate methods. The methods return and keep your result as both an associative and indexed array. Iterating through table rows is as easy as:
$SQL->GetRows('RowTemplate.tpl', 'StoredProcedure', 'Parameters');
FYI This is part of a bigger $Portal framework object in case you're wondering what the $Portal reference is to. $SQL merely extends $Portal.
I hope this helps. Good luck
class SQL {
/********** MEMBER VARIABLES **********************************************************************/
var $Connection; // DB connection handler
var $Result; // ResultSet returned from last call during life of object instance
var $RowCount; // RowCount for ResultSet returned from last call during life of object instance
var $ResultArray; // ResultSet Array returned from last call during life of object instance
var $Query; // Query last submitted during life of object instance
var $ErrorNumber; // Error number for error returned from last call during life of object instance
var $Error; // Error returned from last call during life of object instance
var $Message; // Messages returned during life of object instance
// Switches, flags, markers, etc
var $DebugMode;
var $LogActive;
var $ShowErrorMsg;
// Modules array
var $Modules;
// SQL Connection Info - PROTECTED!
protected $Host = "localhost";
protected $User = "mydatabase";
protected $Password = "mypassword";
protected $Schema = "myschema";
/********** MEMBER FUNCTIONS **********************************************************************/
// Object Constructor
function __construct() {
// Automatically open DB Connection
//$this->OpenDBConnection();
//echo "User Object Constructor<br>";
}
// Open new DB Connection
function OpenDBConnection() {
return ($this->Connection = mysqli_connect($this->Host, $this->User, $this->Password, $this->Schema))? true : false;
}
// Close DB Connection
function CloseDBConnection() {
mysqli_close($this->Connection);
//return true;
}
// Return error messages
function GetError() {
return $this->Error;
}
// Return last query string
function GetQuery() {
return $this->Query;
}
// Call, execute stored procedure and return result set
/* NOTES: The result set is always returned as an int array of associative arrays
That is, if $Result was returned, the first row would be referenced as $Result[0]
and any column of the first row would be referenced as $Result[0]['ColumnName']
COMMENTS: */
function CallProcedure($StoredProcedure) {
// Clear any System Errors
$this->ErrorNumber = '';
$this->Error = '';
// Open DB Connection
if(!$this->OpenDBConnection()) return false;
// Kill error if there are no extra Params passed
$Params = #func_get_arg(1);
// Build Query
$this->Query = "CALL $StoredProcedure ($Params)";
//if($this->Result = $this->Connection->query($this->Query)) {
if($this->Result = mysqli_query($this->Connection, $this->Query)) {
// Reset global Result Set
$this->ResultArray = Array();
// Set record count for current record set
$this->RowCount = 0;
while($Row = #mysqli_fetch_array($this->Result, MYSQLI_BOTH)) {
$this->ResultArray[$this->RowCount] = $Row;
$this->RowCount++;
}
// Close DB Connection
$this->CloseDBConnection();
return $this->ResultArray;
}
// Grab Error
$this->ErrorNumber = mysqli_errno($this->Connection);
$this->Error = mysqli_error($this->Connection);
// Close DB Connection
$this->CloseDBConnection();
return false;
}
/* Using Smarty class, return row template filled with record set from given stored procedure
EXAMPLE 1: Primary Function - Using data set from stored procedure
$Portal->SQL->GetRows('RowTemplate.tpl', 'StoredProcedure', 'Parameters');
EXAMPLE 2: Secondary Function - Using data set in second dimensional associative array
$Portal->SQL->GetRows('RowTemplate.tpl', 'ARRAY', $MyDataSetArray); */
function GetRows($RowTemplate, $Procedure) {
// Kill error if there are no extra Params passed
$Parameters = #func_get_arg(2);
// Set return string
$ReturnString = '';
// If Procedure is ARRAY then params are data set else Call procedure and return results array
$Result = ($Procedure=='ARRAY')? $Parameters : $this->CallProcedure($Procedure, $Parameters);
// Loop through result set initializing smarty obj for each row
$Count = 0;
while(IsSet($Result[$Count])) {
$RowTemplateObj = new Smarty;
$RowTemplateObj->assign('SCRIPT_NAME', SCRIPT_NAME);
$RowTemplateObj->assign('HOST_NAME', HOST_NAME);
// Loop though each result row as an associative array of column - values
foreach ($Result[$Count] as $Key => $Value) {
if(IsSet($Result[$Count][$Key])) $RowTemplateObj->assign($Key, (is_array($Value))?$Value:stripslashes($Value));
//if(IsSet($Result[$Count][$Key])) $RowTemplateObj->assign($Key, $Value);
}
$RowTemplateObj->assign('bgcolor', '{$bgcolor'. ($Count%2 + 1) .'}');
// Concatenate populated row into return string
$ReturnString .= $RowTemplateObj->fetch($RowTemplate);
$Count++;
}
return $ReturnString;
}
function GetSelectList($Procedure, $Parameters, $OptionValueField, $OptionNameField) {
// Kill error if there are no extra Params passed
$Selected = #func_get_arg(4);
// Set return string
$ReturnString = '';
// Get List Resultset
$Result = $this->CallProcedure($Procedure, $Parameters);
// Loop through result set and set <option> ta row
$Count = 0;
while(IsSet($Result[$Count])) {
$ReturnString .= '<option value="'.$Result[$Count][$OptionValueField].'"';
$ReturnString .= ($Selected==$Result[$Count][$OptionValueField])? ' selected ' : '';
$ReturnString .= '>'.$Result[$Count][$OptionNameField].'</option>';
$Count++;
}
return $ReturnString;
}
function Execute($SQL) {
// Clear any System Errors
$this->ErrorNumber = '';
$this->Error = '';
// Open DB Connection
if(!$this->OpenDBConnection()) return false;
// Assign Query
$this->Query = $SQL;
if($this->Result = mysqli_query($this->Connection, $this->Query)) {
// Reset global Result Set
$this->ResultArray = Array();
// Set record count for current record set
$this->RowCount = 0;
while($Row = #mysqli_fetch_array($this->Result, MYSQLI_BOTH)) {
$this->ResultArray[$this->RowCount] = $Row;
$this->RowCount++;
}
// Close DB Connection
$this->CloseDBConnection();
return $this->ResultArray;
}
// Grab Error
$this->ErrorNumber = mysqli_errno($this->Connection);
$this->Error = mysqli_error($this->Connection);
// Close DB Connection
$this->CloseDBConnection();
return false;
}
MAKE Saperate connections in same file and close them according.
/*****Connection for portal1 ******/
$portal1_link = mysql_connect('localhost','root','') or die('Cannot connect to the DB');
mysql_select_db('mylekha_auction',$portal1_link) or die('Cannot select the DB');
/*****Connection for portal2 ******/
$portal2_link = mysql_connect('localhost','root','') or die('Cannot connect to the DB');
mysql_select_db('mylekha_auction',$portal2_link) or die('Cannot select the DB');
I'm gonna make this too complicated, just going to break it down to the main parts.
I have a form that changes the boolean of a variable when the form gets submitted, however it gets called by a function, the function has to change the variable.
class updates
{
var $yesno = false;
function updateBool()
{
$this->yesno = true;
}
}
So when the form gets submitted, it will call $up->updateBool() to change the boolean to true. When I do var_dump($up->yesno), it says false when it should be true. If I do this:
class updates
{
var $yesno = false;
function updateBool()
{
$this->yesno = true;
var_dump($this->yesno); // <-- outputs true
}
}
So how come I cannot get the variable to print out true in a seperate script?
EDIT:
$sql = "SELECT boolean
FROM config
WHERE boolean = 'true'";
$result = mysql_query($sql);
if(mysql_num_rows($result) > 0)
{
$up->updateBool();
}
else
{
header("Location: index.php?d=none");
}
This is part of the code where it gets called. I can confirm there are more than 1 record in the SQL statement.
So when the form gets submitted, it will call $up->updateBool() to change the boolean to true
You seem to be switching to a new page, where $up will be a new object. Objects do not persist across requests. PHP "loses its memory" when you call a new page, and all variables are started from scratch.
To persist values across page requests, you would need to use something like sessions.
class updates
{
public $yesno;
function __construct(){
$this->yesno = false;
}
function updateBool()
{
$this->yesno = true;
}
}
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