Close session after executing database query - php

I have very little experience with joomla and sql and I would really appreciate your help!
I am using joomla 2.5 and I am querying data from the database and storing it in memory with the following code:
function getList()
{
$mainframe = JFactory::getApplication('site');
$db = JFactory::getDBO();
$query = " SELECT
*
FROM
#__ListUser
WHERE
$db->setQuery( $query );"
$rows = $db->loadObjectList();
return $rows;
}
I have 3 questions,
When I query the database, a new DB session is opened, Do I need to close it after or is automatic?
Do you know of a more efficient way to achieve this method (a user session memory size is about 11MB!)
Is there any security issue with accessing the database using this method?
Thank you very much! any help would be very appreciated!

The code should look like this (I don't see how it can work now):
function getList()
{
// $mainframe = JFactory::getApplication('site'); // you don't need this line!
$db = JFactory::getDBO();
$query = " SELECT
*
FROM
#__ListUser
WHERE
1=1"; // just some condition to extract selected rows
$db->setQuery( $query ); // this sets the query and it's joomla, not sql.
$rows = $db->loadObjectList();
return $rows;
}
Please note the WHERE .... needs a condition (else if you want all the rows, remove WHERE and what follows)
You don't need to close it
11Mb is not necessarily due to that query, try adding LIMIT 0,1 (to return just one row) you'll see your memory doesn't change much. Turn on debug in the global configuration, and reload the component. At the very bottom of the page you'll see which extensions are eating up your memory. 11Mb is acceptable though on most installations.
Should you create your WHERE condition using input params, just make sure you $db->quote() any values to prevent SQL-injection.

Try
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select($db->quote('*')
->from($db->quoteName('#__Listuser') // Do you really have upper case there?
->where('your condition with proper quoting');
$db->setQuery($query);
$rows = $db->loadObjectList();

1.
UNCOOL:
If you want to close or disconnect the database-session, you may use:
$db->disconnect(); // See: http://api.joomla.org/cms-3/classes/JDatabaseDriver.html#method_disconnect
But i guess, that the database-connection for every other module, plugin or template that want to use JFactory::getDBO(); is also closed then and needs to be reopened.
BETTER:
You should use FREE RESULT instead after a query is transfered to a PHP-Variable: http://api.joomla.org/cms-3/classes/JDatabaseDriverMysql.html#method_freeResult
$db->freeResult();

Related

How to build a custom PHP Mysql or PDO function

Recently I seem to be writing nearly the same sql statements and I have to use PHP for looping and error reporting, so I'm trying to write something general that will shorten my code extensively. I'm still learning programming.
I don't know if I need to use classes or what, but here's an example of what I'm trying to do.
/////////q = query, f = fetch type(loop or single object), r = row;
function dbQuery($q, $f, $r){
global $con;
$query = mysqli_query($con, $q) or die(mysqli_error($con));
if ($f = 'loop'){
while($row = mysqli_fetch_array($query)){
echo $r;
}
} else if ($f='single'){
$row = mysqli_fetch_array($query);
echo $r;
}
///////////or prepared statements//////////
}
dbQuery("SELECT * FROM music WHERE perms = 'a' limit 50", $f='loop', $r="<div>".$row['title']."</div>"
);
I want something like the following, I know its not write but I want to be able to have the function above return row results to the function's arg.
dbQuery($f='loop'){ /////////// I really don't know the corrent way for this////
$q= "SELECT * FROM music WHERE perms = 'a' limit 50";
$r="<div>".$row['title']."</div>";
////////and breaking out of php////
?>
<section><?php echo $row['duration']; ?></section>
<?php
}
Please do recommend materials I can check out.
I will recommend you to use some framework like Laravel or some query builder class. There are tons of them. If for some reason, you will like to create your own, please do not use mysql function, since is deprecated. Personally, I will prefer PDO over mysqli (this is just a preference) make sure to prepare statements. Check this link out, it will help you with your project
http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
Good luck with your project.

echo full joomla query (with limit etc)?

I was wondering if there was a way to echo out the full query with limit and limitstart etc. I can echo out the line $query, but i want to see why the limit isn't working and I can't seem to get it to display the actual query that it's sending to the database.. Here's the code:
$params =& JComponentHelper::getParams('com_news');
$limit = $params->get('x_items', 5);
$limitstart = JRequest::getVar('limitstart', 0);
$query = "SELECT * FROM #__news WHERE published = 1 AND catid = ".$Itemid." ORDER BY date DESC";
$db->setQuery($query, $limitstart, $limit);
$rows = $db->loadObjectList();
$db->getQuery($query, $limitstart, $limit); is only displaying "SELECT * FROM jos_news WHERE published = 1 AND catid = 8 ORDER BY date DESC" which doesnt have the LIMIT params on the end of the query..
Any help would be appreciated :)
The JDatabaseQuery object has a __toString() function that outputs the query so you can do:
echo $db->getQuery();
Or if you want to pass it to a function you can explicitly cast it to a string first:
var_dump((string)$db->getQuery());
var_dump($db);die;
Do that after the loadObjectList() call. Inside the $db variable there must be a _sql attribute that is the last query executed.
Agreed with the previous answers, but... In case you are developing your own components, since I often want to know for sure what exactly is executed too, here's a simple solution:
In your models put:
$db = JFactory::getDBO();
echo $db->getQuery();
Where you want to know the query... Don't put it in (for example) your view, since it might have loaded some other dropdown list by way of execution in the meantime...
For example:
For a list-view put it right before the foreach ($items... in the public function getItems() of the model.
In a form-/item-view put it right before the return $data / return $item in the protected function loadFormData() / public function getItem($pk = null)
Hope this helps...
On new joomla versions, you need to echo __toString() on query object.
echo $query->__toString();
I get this info on this joomla answer.
Hope this helps
Joomla provides $query->dump(). To add convenience, I like to wrap it in enqueueMessage() so that the presented string is at the top of the webpage.
JFactory::getApplication()->enqueueMessage(
$query->dump(),
'notice'
);
IMPORTANT: You should never show the raw SQL string or a raw query error string to the public.
See some of my implementations at Joomla Stack Exchange.

MySQL query within foreach loop

I want to show all text messages from db where id=$e ($err is an array).
Inserted the query into the foreach loop, it works well but it does extra work (does query for every value of array).
Is there any other way to do it (i mean extract query from foreach loop)?
My code looks like this.
foreach ($err as $e)
{
$result = $db -> query("SELECT * from err_msgs WHERE id='$e'");
$row = $result -> fetch_array(MYSQLI_BOTH);
echo "<li><span>".$row[1]."</span></li>";
}
It is much more efficient to do this with implode() because it will only result in one database query.
if (!$result = $db->query("SELECT * FROM `err_msgs` WHERE `id`='".implode("' OR `id`='",$err)."'")) {
echo "Error during database query<br />\n";
// echo $db->error(); // Only uncomment this line in development environments. Don't show the error message to your users!
}
while ($row = $result->fetch_array(MYSQLI_BOTH)) {
echo "<li><span>".$row[1]."</span></li>\n";
}
Check the SQL IN clause.
Firstly, a bit of a lecture: embedding strings directly into your queries is going to cause you trouble at some point (SQL injection related trouble to be precise), try to avoid this if possible. Personally, I use the PDO PHP library which allows you to bind parameters instead of building up a string.
With regard to your question, I'm not sure I have understood. You say that it does extra work, do you mean that it returns the correct results but in an inefficient way? If so then this too can be addressed with PDO. Here's the idea.
Step 1: Prepare your statement, putting a placeholder where you currently have '$e'
Step 2: Loop through $err, in the body of the loop you will set the place holder to be the current value of $e
By doing this you not only address the SQL injection issue, you can potentially avoid the overhead of having to parse and optimise the query each time it is executed (although bear in mind that this may not be a significant overhead in your specific case).
Some actual code would look as follows:
// Assume that $dbdriver, $dbhost and $dbname have been initialised
// somewhere. For a mysql database, the value for $dbdriver should be
// "mysql".
$dsn = "$dbdriver:host=$dbhost;dbname=$dbname";
$dbh = new PDO($dsn, $dbuser, $dbpassword);
$qry = "SELECT * from err_msgs WHERE id = :e"
$sth = $dbh->prepare($qry);
foreach ($err as $e) {
$sth->bindParam(":e", $e);
$sth->execute();
$row = $sth->fetch();
// Prints out the *second* field of the record
// Note that $row is also an associative array so if we
// have a field called id, we could use $row["id"] to
// get its value
echo "<li><span>".$row[1]."</span></li>";
}
One final point, if you want to simply execute the query once, instead of executing it inside the loop, this is possible but again, may not yield any performance improvement. This could be achieved using the IN syntax. For example, if I'm interested in records with id in the set {5, 7, 21, 4, 76, 9}, I would do:
SELECT * from err_msgs WHERE id IN (5, 7, 21, 4, 76, 9)
I don't think there's a clean way to bind a list using PDO so you would use the loop to build up the string and then execute the query after the loop. Note that a query formulated in this way is unlikely to give you any noticable performance improvment but it really does depend on your specific circumstances and you'll just have to try it out.
You can do this much simpler by doing
$err_csv = implode("','",$err);
$sql = "SELECT FROM err_msgs WHERE id IN ('$err_csv')";
$result = $db -> query($sql);
while ($row = $result -> fetch_array(MYSQLI_BOTH))
{
echo "<li><span>".$row[1]."</span></li>";
}
That way you don't have to keep sending queries to the database.
Links:
http://php.net/manual/en/function.implode.php

magento make multiple database connections without losing array values

I am trying to make connections to two different databases so my script should work as follows
Find all orders for the current logged in customer where the order state is complete, it is a virtual product and it has a juno order id (this query works fine)
Collect all of order ids that have been found and store them in an array (this works fine)
now connect to sales_order_items and for each item that is part of an order id check to see if the database has a url download link,
if not i will connect to an api --
the problem is when i want to make my second connection i seem to lose all the values that are stored in the $orderIds array.
i have been looking for solutions but i am pretty new to the zend framework
any help would be much appreciated
my script is as follows
$conn = Mage::getSingleton('core/resource')->getConnection('core_write');
$result = $conn->query('select * from sales_flat_order WHERE customer_id='.$session->getCustomerId().' AND state="complete" AND is_virtual=1 AND juno_order_id!="null"');
$orderIds=array();
foreach ($result as $orderId)
{
$orderIds[]=$orderId[entity_id];
$itemsonOrder=$conn->query('select * from sales_flat_order_items WHERE order_id='.$order[entity_id]);
}
// value of first array $orderIds gets lost if i make annother connection using $conn
echo 'items on order';
print_r($itemsonOrder);
echo '<pre>';
print_r($orderIds);
echo '</pre>';
Well you aren't done with the first query yet when you are connecting with the second query. Go ahead and finish with the first query, then start the second one. Try something more like this...
$conn = Mage::getSingleton('core/resource')->getConnection('core_write');
$result = $conn->query('select * from sales_flat_order WHERE customer_id='.$session->getCustomerId().' AND state="complete" AND is_virtual=1 AND juno_order_id!="null"');
$orderIds=array();
foreach ($result as $orderId)
{
$orderIds[]=$orderId[entity_id];
}
foreach ($orderIds as $orderId)
{
$itemsonOrder=$conn->query('select * from sales_flat_order_items WHERE order_id='.$orderId);
}
Also, you should probably make sure you are using parameters when doing queries. Concatenating sql strings like that can be dangerous (leaves you open to vulnerabilities sometimes). For example,
$conn->query('select * from sales_flat_order_items WHERE order_id='.$orderId);
should be changed to
$conn->query('select * from sales_flat_order_items WHERE order_id=?', array($orderId));
Also, do you really need to "select *"??? I mean, just select the columns you need.

Is it best to make fewer calls to the database and output the results in an array?

I'm trying to create a more succinct way to make hundreds of db calls. Instead of writing the whole query out every time I wanted to output a single field, I tried to port the code into a class that did all the query work. This is the class I have so far:
class Listing {
/* Connect to the database */
private $mysql;
function __construct() {
$this->mysql = new mysqli(DB_LOC, DB_USER, DB_PASS, DB) or die('Could not connect');
}
function getListingInfo($l_id = "", $category = "", $subcategory = "", $username = "", $status = "active") {
$condition = "`status` = '$status'";
if (!empty($l_id)) $condition .= "AND `L_ID` = '$l_id'";
if (!empty($category)) $condition .= "AND `category` = '$category'";
if (!empty($subcategory)) $condition .= "AND `subcategory` = '$subcategory'";
if (!empty($username)) $condition .= "AND `username` = '$username'";
$result = $this->mysql->query("SELECT * FROM listing WHERE $condition") or die('Error fetching values');
$info = $result->fetch_object() or die('Could not create object');
return $info;
}
}
This makes it easy to access any info I want from a single row.
$listing = new Listing;
echo $listing->getListingInfo('','Books')->title;
This outputs the title of the first listing in the category "Books". But if I want to output the price of that listing, I have to make another call to getListingInfo(). This makes another query on the db and again returns only the first row.
This is much more succinct than writing the entire query each time, but I feel like I may be calling the db too often. Is there a better way to output the data from my class and still be succinct in accessing it (maybe outputting all the rows to an array and returning the array)? If yes, How?
Do you actually have a performance issue?
If your current setup works and doesn't suffer from performance issues, I wouldn't touch it.
This sort of DB access abstraction will likely become a maintenance issue and probably won't help performance.
Also, you're susceptible to SQL injection.
You should be able to store the whole object from the query into a variable and then access the single values from that object:
$object = $listing->getListingInfo('','Books');
$title = $object->title;
$price= $object->price;
But you can also use fetch_assoc() and return the whole assiciative array:
$array = $listing->getListingInfo('','Books');
$title = $object['title'];
$price= $object['price'];
This will give you the same results and also with only one query to the DB.
EDIT: If the getListingInfo() is the only function you should think of the following:
rename the function to prepareListingInfo() and within the function only prepare the query and store it in a class variable.
add a getNextListingInfo() function, which will return an object or associative array with the next row.
Using this new function, you can get every row that matches your query.
Either cache the result in an internal var
Or Comment it with a warning and explain to function users to copy the result in an var instead of calling it again and again with the same params
Yes, that would be calling the db too often.
A couple of solutions
1) put the listing info in a variable
2) cache the results in a hashmap or dictionary (be careful for memory leaks)

Categories