PDO Memcached PHP - php

I'm trying to implement memcached into my server due to how large the database gets so quickly. I was wondering how I'm able to implement it into this code:
function getWorkers($db)
{
$meminstance = new Memcache();
$meminstance->pconnect('localhost', 11211);
$del = $db->prepare('SELECT DISTINCT(address) from works');
$del->execute();
$arr = $del->fetchAll();
$works = getMaxWork($db);
foreach($arr as $a)
{
$del = $db->prepare('SELECT * FROM works WHERE address = \'' . $a[0] . '\'');
$del->execute();
$work = $del->rowCount();
echo '<tr>';
echo '<td>' . htmlspecialchars($a[0], ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td>' . $work . '</td>';
echo '<td>' . round(intval($work)/intval($works)*100, 2) . '</td>';
echo '</tr>';
}
}

Here you go
function getData($db)
{
$meminstance = new Memcache();
$meminstance->pconnect('localhost', 11211);
$sqlQuery = 'SELECT DISTINCT(address) from works';
$memcacheKey = md5($sqlQuery);
if ( $arr = $meminstance->get(memcacheKey) )
{
// its in cache do nothing
}
else
{
// its not in cache, so we came here, lets now get it from db and cache it
$del = $db->prepare($sqlQuery);
$del->execute();
$arr = $del->fetchAll();
$works = getMaxWork($db);
// lets now cache it
$meminstance->set(memcacheKey,$arr);
}
foreach($arr as $a)
{
$sqlQuery = 'SELECT * FROM works WHERE address = \'' . $a[0] . '\'';
$memcacheKey = md5($sqlQuery);
if ( $del = $meminstance->get($memcacheKey))
{
//its in cache yaaaaaaaa :D
}
else
{
$del = $db->prepare('SELECT * FROM works WHERE address = \'' . $a[0] . '\'');
$del->execute();
$work = $del->rowCount();
// lets cache it here
$meminstance->set($memcacheKey,$del);
}
echo '<tr>';
echo '<td>' . htmlspecialchars($a[0], ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td>' . $work . '</td>';
echo '<td>' . round(intval($work)/intval($works)*100, 2) . '</td>';
echo '</tr>';
}
}
The logic when you are using memcache in your website. Is it md5 the sql queries so they will be unique. You first try to fetch from memcached, ( you md5 the sql Query) so it will be the key. if you dont get anything, you get the data from database and then save it into memcache. Which means you md5 the sql Query to make they key so it will be unique, and you pass the returned result from database as its value
key ===> md5(Sql Query )
value ==> the object, result set that is fetched from database
// pseudocode
if ( Get data from memcache passed )
{
return result;
}
else
{
get the data from database
save it into memcache
}
Note: If you are running on a single server, better to look into APC rather than memcached

Related

Display all matching values rather than the first

I have created a query which I am using to display reports. The query gets data from a few different tables which is fine, although I cannot figure out how to echo more than one matching value within a table. For example the table vtiger_addisa has more than one newcurrentamount which I need displayed.
$sql = $adb->query("SELECT *
FROM vtiger_isa, vtiger_addisa, vtiger_contactdetails
WHERE vtiger_isa.relatedclient = vtiger_addisa.addrelatedclient
AND vtiger_addisa.addrelatedclient = vtiger_contactdetails.contactid
AND vtiger_isa.relatedclient = $relatedclient
AND vtiger_isa.policynumber = $policynumber");
//Uncomment lines below for testing sql
//echo $sql;
//exit;
while ($sql->fetchInto($row)) {
// Assuming DB's default fetchmode is DB_FETCHMODE_ORDERED
echo $row['firstname'] . "\n";
echo $row['lastname'] . "\n";
echo $row['policynumber'] . "\n";
echo $row['newcurrentamount'] . "\n";
echo $row['newcurrentamount'] . "\n";
echo $row['currentamount'] . "\n";
exit;
}
You can get Multiple Row result as below.
global $adb;
$sql = $adb->query("SELECT * FROM vtiger_isa, vtiger_addisa, vtiger_contactdetails
WHERE vtiger_isa.relatedclient = vtiger_addisa.addrelatedclient
AND vtiger_addisa.addrelatedclient = vtiger_contactdetails.contactid
AND vtiger_isa.relatedclient = $relatedclient
AND vtiger_isa.policynumber = ?");
$params = array($policynumber);
$result = $adb->pquery($query, $params);
$noOfRows = $db->num_rows($result);
for($i=0; $i<$noOfRows; ++$i) {
$firstname = $db->query_result($result, $i, "firstname");
$lastname = $db->query_result($result, $i, "lastname");
$policynumber = $db->query_result($result, $i, "policynumber");
$newcurrentamount = $db->query_result($result, $i, "newcurrentamount");
$currentamount = $db->query_result($result, $i, "currentamount");
}
Use 'as' operator
select newcurrentamount as a, newcurrentamount as b from vtiger_addisa
P.S- Try avoiding ' * ' and use only the necessary columns.

Issue with duplicate data in array and SQL

I have this function that reads the contents of an array, and outputs data form a mysql database into a table. However, when there are duplicated in the array, it only lists that information once. In the code below, it will only give me three table rows, 1, 100 and 140. It skips over the second instance of 1. How would I fix that to output the data into the table regardless of there being duplicates?
$con = mysql_connect('localhost', 'root', 'password');
$table = "cwr";
$player1pod1 = array(1, 1, 100, 140);
function generatelistplayer1 ($player1pod1, $con, $table){
$sql = "SELECT * FROM $table WHERE id IN (".implode(',',$player1pod1).")";
$myData = mysql_query($sql, $con);
echo "<table border='1' cellpadding='2'> ";
while($row = mysql_fetch_array( $myData )) {
echo "<tr>";
echo '<td>' . $row['id'] . '</td>';
echo '<td>' . $row['cardname'] . '</td>';
echo '<td>' . $row['rarity'] . '</td>';
}
echo "</table>";
Desired output for the table is :
1
1
100
140
I'm getting :
1
100
140
It's only going to give you 3 rows, because it's only going to give you unique rows. You can instead use a UNION query if you want actual duplicates.
"SELECT * FROM $table WHERE id = 1 UNION ALL SELECT * FROM $table WHERE id IN (".implode(',',$player1pod1).")";
If you want to use the array, you can create a loop:
$query = [];
foreach($player1pod1 as $pod) {
$query[] = "SELECT * FROM $table WHERE id = $pod";
}
$sql = implode(" UNION ALL ",$query);
Fetch all the results first (into an array, key is the id), then based on your original list, display each result.
You can print the result as many times as you need in a loop.
Notice its not a loop on the query. Query to db will be done only once, and I do not recommend a solution which do multiple queries or query same data more than once.
If order is not important i.e array(1, 100, 1, 140) = is good as = array(1, 1, 100, 140) , we can use array_count_values($player1pod1) and print each result as much as needed:
$con = mysql_connect('localhost', 'root', 'password');
$table = "cwr";
$player1pod1 = array(1, 1, 100, 140);
function generatelistplayer1 ($player1pod1, $con, $table)
{
$counts = array_count_values($player1pod1);
$sql = "SELECT * FROM $table WHERE id IN (" . implode(',', $player1pod1) . ")";
$myData = mysql_query($sql, $con);
echo "<table border='1' cellpadding='2'> ";
while ($row = mysql_fetch_array($myData)) {
for ($i=0;$i<count($counts[$row['id']]);$i++) {
echo "<tr>";
echo '<td>' . $row['id'] . '</td>';
echo '<td>' . $row['cardname'] . '</td>';
echo '<td>' . $row['rarity'] . '</td>';
}
}
echo "</table>";
}
In case that the order is do important we can first collect data from the databse sql, and then to print it one by one, with "print_rows" function in my example. In this solution we don't need to count the values but we use some RAM to hold the sql results:
function generatelistplayer1 ($player1pod1, $con, $table)
{
$sql = "SELECT * FROM $table WHERE id IN (" . implode(',', $player1pod1) . ")";
$myData = mysql_query($sql, $con);
//extract data
$sql_data = array();
while ($row = mysql_fetch_array($myData)) {
$sql_data[$row['id']] = array( 'cardname'=> $row['cardname'],'rarity'=> $row['rarity']);
}
//print data
print_rows($player1pod1,$sql_data);
}
function print_rows($player1pod1, $mysql_data)
{
echo "<table border='1' cellpadding='2'> ";
for($i=0;$i<count($player1pod1);$i++) {
echo "<tr>";
echo '<td>' . $player1pod1[$i] . '</td>';
echo '<td>' . $mysql_data[$player1pod1[$i]['cardname']] . '</td>';
echo '<td>' . $mysql_data[$player1pod1[$i]['rarity']] . '</td>';
}
echo "</table>";
}

Display message if odbc_num_rows == empty

I have an advanced search query which queries a database. The search works fine and prints the desired results when a user searches something that is IN the database.
I've set up a condition when if a user searches something and that something couldn't be found in the database, it displays a message that the record could not be found.
But it's not displaying the message I need it to. Instead, if it can't find the record, it prints an empty table with headings. This table is only supposed to be printed if something is found.
No if I swop the condition from >= -1 to just == -1 it displays the message I need it to when something couldn't be found even if that something is in the database.
I hope this makes sense.
Please see my code below.
<table class="table table-bordered table-striped" style="width: 100%;">
<?php
$dbName = "F:/Domains/autodeal/autodeal.co.za/wwwroot/newsite/db/savvyautoweb.mdb";
// Throws an error if the database cannot be found
if (!file_exists($dbName)) {
die("Could not find database file.");
}
// Connects to the database
// Assumes there is no username or password
$conn = odbc_connect("Driver={Microsoft Access Driver (*.mdb)};Dbq=$dbName", '', '');
$searchMake = addslashes($_POST['makeSelection']);
$searchModel = addslashes($_POST['modelSelection']);
$searchBranch = addslashes($_POST['branchSelection']);
$searchYear = addslashes($_POST['yearSelection']);
$minPrice = addslashes($_POST['minPriceSelection']);
$maxPrice = addslashes($_POST['maxPriceSelection']);
$sql = "SELECT Id, Make, Model, Year, Price, SpecialPrice, Branch, StockNO FROM Vehicle ";
if ($searchMake || $searchModel || $searchBranch || $searchYear || $minPrice || $maxPrice) {
$sql .= "WHERE ";
}
$combine = '';
if ($minPrice) {
$sql .="{$combine}Price BETWEEN $minPrice "; $combine = 'BETWEEN ';
}
if ($maxPrice) {
$sql .="AND $maxPrice "; $combine = 'AND ';
}
if ($searchMake) {
$sql .="{$combine}Make LIKE '%$searchMake%' "; $combine = 'AND ';
}
if ($searchModel) {
$sql .="{$combine}Model LIKE '%$searchModel%' "; $combine = 'AND ';
}
if ($searchBranch) {
$sql .="{$combine}Branch LIKE '%$searchBranch%' "; $combine = 'AND ';
}
if ($searchYear) {
$sql .="{$combine}Year LIKE '%$searchYear%' "; $combine = 'AND ';
}
$rs = odbc_exec($conn, $sql);
if (odbc_num_rows($rs) >= -1) {
echo "\t" . "<tr>\n";
echo "\t" . "<th>Make</th><th>Model</th><th>Year</th><th>Price</th><th>Special Price</th><th>Location</th><th>Stock Number</th>" . "\n";
while (odbc_fetch_row($rs)) {
$id = odbc_result($rs, Id);
$make = odbc_result($rs, Make);
$model = odbc_result($rs, Model);
$year = odbc_result($rs, Year);
$price = odbc_result($rs, Price);
$specialPrice = odbc_result($rs, SpecialPrice);
$branch = odbc_result($rs, Branch);
$stockNo = odbc_result($rs, StockNO);
echo "\t" . "<tr>\n";
echo "\t\t" . "<td><a href=/newsite/selected-vehicles?Id=$id>" . $make . "</td><td><a href=/newsite/selected-vehicles?Id=$id>" . $model . "</a></td><td>" . $year . "</td><td>" . $price . "</td><td>" . $specialPrice . "</td><td>" . $branch . "</td><td>" . $stockNo . "</td>\n";
echo "\t" . "</tr>\n";
}
} else {
echo "We don’t have the vehicle you are looking for right now, but send us your vehicle requirements and we will be sure to find you one!";
}
odbc_free_result($rs);
odbc_close($conn);
// This message is displayed if the query has an error in it
if (!$rs) {
exit("There is an error in the SQL!");
}
?>
</table>
As a general rule, odbc_num_rows() is not a reliable way to determine the number of rows returned by a SELECT query. As mentioned in the "Notes" section of the PHP documentation:
Note:
Using odbc_num_rows() to determine the number of rows available after a SELECT will return -1 with many drivers.
That is indeed the case with the Access ODBC driver.
Instead of using odbc_num_rows() you could check the result of the first odbc_fetch_row() to see if it is TRUE and, if so, proceed with dumping the data to the HTML table. If the first call to odbc_fetch_row() returns FALSE then no rows were retrieved and you can display your message.

Display COLUMN NAMES from database through PHP

I am trying to pull all the column names from my database 'settings' and list them in PHP.
A bit of research has come up with the following:
SHOW COLUMNS FROM settings
but I don't know how to go about listing these off through PHP.
it would be helpful if any code posted was a prepared statement format, but not required.
Here is my PHP, it's giving me this error:
Notice: Undefined index: sThumbWidth in /home/demomycm/public_html/subdomains/mercury/eshop/library/classes/class.settings.php on line 204
for every field in my database.
$loadColumns = array();
$query = "SHOW COLUMNS FROM settings";
$result = $this->glob->dbConn->query($query);
if($this->glob->dbConn->errno) {
trigger_error('An error occurred whilst loading counties from the database.' . PHP_EOL . 'Query: ' . $query . PHP_EOL . 'Error[' . $this->glob->dbConn->errno . ']: ' . $this->glob->dbConn->error, E_USER_WARNING);
} elseif($result->num_rows) {
while($row = $result->fetch_assoc()) {
$loadColumns[$row['Field']];
}
return $loadColumns;
}
$loadColumnsHtml = '';
$loadColumns = $this->Settings->LoadColumns();
foreach($loadColumns as $i => $field) {
$loadColumnsHtml .= '<div class="home-stat-small-link">' . ($i + 1) . '. <strong>' . $field['Field'] . '</strong>.</div>';
}
use describe
DESCRIBE my_table;
Or in newer versions you can use INFORMATION_SCHEMA:
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'my_database' AND TABLE_NAME = 'my_table';
In your code you have $loadColumns as an array.
This line does nothing: $loadColumns[$row['Field']];
Basically your getting the value in $loadColumns with the key associated with $row['Field'] and not assigning anything.
You want something like this perhaps for that line:
array_push($loadColumns,$row['Field']);
Full code below
$loadColumns = array();
$query = "SHOW COLUMNS FROM settings";
$result = $this->glob->dbConn->query($query);
if($this->glob->dbConn->errno) {
trigger_error('An error occurred whilst loading counties from the database.' . PHP_EOL . 'Query: ' . $query . PHP_EOL . 'Error[' . $this->glob->dbConn->errno . ']: ' . $this->glob->dbConn->error, E_USER_WARNING);
} elseif($result->num_rows) {
while($row = $result->fetch_assoc()) {
array_push($loadColumns,$row['Field']); //<-- this line has been changed
}
return $loadColumns;
}
$loadColumnsHtml = '';
$loadColumns = $this->Settings->LoadColumns();
foreach($loadColumns as $i => $field) {
$loadColumnsHtml .= '<div class="home-stat-small-link">' . ($i + 1) . '. <strong>' . $field['Field'] . '</strong>.</div>';
}
On MySQL connection (deprecated) you can use:
mysql_list_fields
On PDO (recommend) use:
$query = $dbh->prepare("DESCRIBE tablename");
$query->execute();
$tableFields = $query->fetchAll(PDO::FETCH_COLUMN);
On PDO you can also use PDOStatement::getColumnMeta(). But it has the status: EXPERIMENTAL

Too Many Connections; db connect in a function

I'm currently updating my PHP knowledge and I've stumbled upon a problem whilst grabbing data from my database.
The problem I have in itself could probably be sorted with the max_connection setting (yes, I've searched around), but I believe it might be a work-around, since I don't want to change base settings, if not so needed.
I have three "steps" in my little "ladder";
My main is a ladder, every ladder has one (or more) step and every step has one (or more) modules.
So what I'm trying to do is a function that retrieves all of these and shows them. Now, every function has a connection to my database; where the function runs its query and then closes. My first clue was to close the database between every function, which I did - but since I'm retrieving my code "all at once", this doesn't work (see code).
How would I go about making one database connection (maybe in a function) and calling it once, and then retrieving all the information, without opening new connections?
I hope you have all information required to answer my questions, and I hope I'm posting this in a stack overflow way.
Thank you in advance.
P.S: Dunno if I used this code tool right, it looks structured, but it doesn't have highlights?
CODE:
<?php
echo displayResult();
function displayResult() {
$db = new mysqli ('localhost', 'website', 'dog', 'nplus');
$sql = 'SELECT * FROM ladders';
$result = $db->query($sql);
$r = '';
$r .= '<table>';
while ($row = $result->fetch_object()) {
$r .= '<tr>';
$r .= '<td>' . htmlspecialchars($row->ladderID) . '</td>';
$r .= '<td>' . htmlspecialchars($row->ladderName) . '</td>';
$r .= '<td>' . htmlspecialchars($row->created) . '</td>';
$r .= displayAssociateStep($row->ladderID);
$r .= '<tr><td>&nbsp</td></tr>';
}
$r .= '</table>';
$db->close();
return $r;
}
function displayAssociateStep($ladderID) {
$r = '';
$db = new mysqli ('localhost', 'website', 'dog', 'nplus');
$sql = 'SELECT * FROM steps WHERE ladderID = '. $ladderID ;
$result = $db->query($sql);
$r = '';
while ($row = $result->fetch_object()) {
$r .= '<tr>';
$r .= '<td></td>';
$r .= '<td></td>';
$r .= '<td>' . htmlspecialchars($row->stepName) . '</td>';
$r .= '<td>' . htmlspecialchars($row->created) . '</td>';
$r .= '</tr>';
}
$db->close();
return $r;
}
?>
You only need to connect to the database once, and pass it around as an argument, like so:
<?php
function displayResult($db) {
$sql = "
SELECT *
FROM ladders
";
$result = $db->query($sql);
// ADD ERROR CHECKING HERE
// What happens if the query fails?
$r = '<table>';
while ($row = $result->fetch_object()) {
$r .= '<tr>';
$r .= '<td>' . htmlspecialchars($row->ladderID) . '</td>';
$r .= '<td>' . htmlspecialchars($row->ladderName) . '</td>';
$r .= '<td>' . htmlspecialchars($row->created) . '</td>';
$r .= '</tr>';
$r .= displayAssociateStep($db, $row->ladderID);
$r .= '<tr><td colspan="3"> </td></tr>';
}
$r .= '</table>';
return $r;
}
function displayAssociateStep($db, $ladderID) {
// Are you 100% certain $ladderID is always safe to use in a query?
// Does it need escaping?
$sql = "
SELECT *
FROM steps
WHERE ladderID = $ladderID
";
$result = $db->query($sql);
// ADD ERROR CHECKING HERE
// What happens if the query fails?
$r = '';
while ($row = $result->fetch_object()) {
$r .= '<tr>';
$r .= '<td></td>';
$r .= '<td>' . htmlspecialchars($row->stepName) . '</td>';
$r .= '<td>' . htmlspecialchars($row->created) . '</td>';
$r .= '</tr>';
}
return $r;
}
// Connect once
$db = new mysqli ('localhost', 'website', 'dog', 'nplus');
// Pass the connection in as an argument
echo displayResult($db);
// Close the connection
$db->close();
I would say... pass the $db variable you got in displayResult to displayAssociateStep, as an added parameter. Then you don't need to open/close connexion in displayAssociatesStep anymore.
Is it what you want to do?

Categories