Performance of function which connects to database - php

I have a function to check wether a function/module is disabled by an admin or not.
The function looks like this (in functions.php):
function function_enabled($function_module) {
include("dbconnect.php");
if ($function_module == "changelogs" OR $function_module == "news" OR $function_module == "calendar" OR $function_module == "groups" OR $function_module == "settings" OR $function_module == "eat" OR $function_module == "weather" OR $function_module == "usertext" OR $function_module == "login") {
$sql = $db->query("SELECT enabled FROM functions WHERE function_name = '$function_module'");
$row = $sql->fetch_object();
$return = $row->enabled;
return $return;
}
}
And this is how I use the function (in any other php file):
include("functions.php");
if(function_enabled("weather") == 1) {
//do the weather stuff here
} else {
echo"Function disabled";
}
Now my question: How is the performance of this function? Can this cause relative high performance hits? Is there a better/faster way to check wether a function is enabled or not or is this script okay?
UPDATE 1
Now, I combined these multiple queries into one so that all values are in an array.
function compare_id($a, $b) {
if ($a['id'] == $b['id']) return 0;
return ($a['id'] < $b['id']) ? -1 : 1;
}
$sql = $db->query("SELECT function_name, enabled, id FROM functions");
$function_array = array();
while ($row = mysqli_fetch_assoc($sql)) {
$function_array[] = $row;
}
usort($function_array, compare_id);
if($function_array[0]['enabled'] == 1) {
echo"changelogs enabled<br>";
} else {
echo"changelogs disabled<br>";
}
if($function_array[2]['enabled'] == 1) {
echo"calendar enabled<br>";
} else {
echo"calendar disabled<br>";
}
if($function_array[7]['enabled'] == 1) {
echo"usertext enabled<br>";
} else {
echo"usertext disabled<br>";
}
if($function_array[8]['enabled'] == 1) {
echo"login enabled<br>";
} else {
echo"login disabled<br>";
}
if($function_array[4]['enabled'] == 1) {
echo"settings enabled<br>";
} else {
echo"settings disabled<br>";
}
Is this method faster?

It looks OK. Is it giving you issues? There could be performance issues in the DB query from the table or index.
Generally you shouldn't build for performance from the start. Rather build something that functions, then go back an optmise where the choke points are. There are high load webservices which use simple frameworks (Ruby on Rails, Laravel) They only have to optimise 2-5% of the code where the load is. When you know where the choke points are and why its choking you can make an educated choice on how to optmise. Should it be optimised, or should I rewite this in another language.
Does your functions table change fequently? If not you could possibly export it to file. Then PHP could read it once and store it in Memory as an array. Referencing an array would be a lot faster functions['weather'] == 1 with no DB throughput issues.

function function_enabled($function_module) {
$_FUNCTION_MODULE = array ("changelogs", "news", "calendar", "groups", "settings", "eat", "weather", "usertext", "login");
require_once ("dbconnect.php");
if (in_array($function_module, $_FUNCTION_MODULE) {
$query = $db->query("SELECT enabled FROM functions WHERE function_name = '$function_module'");
$row = $query->fetch_object();
$isEnabled = $row->enabled;
return $isEnabled;
}
return NULL;
}

Related

Advice in design about Control Structure else if, switch o a better way?

I made the script to do what is expected, so it work ok but there must be a more elegant way to achieve the same result. I know that using switch will make it look nicer but not sure if the result will be the same as the 'default:' behavior:
This is the section of the script i want to refactor:
foreach ($free_slots as $val) { // here i am looping through some time slots
$slot_out = $free_slots[$x][1];
$slot_in = $free_slots[$x][0];
$slot_hours = $slot_out - $slot_in;
// tasks
if ($slot_out != '00:00:00') {
// Here i call a function that do a mysql query and
// return the user active tasks
$result = tasks($deadline,$user);
$row_task = mysql_fetch_array($result);
// HERE IS THE UGLY PART <<<<<----------------
// the array will return a list of tasks where this current
// users involved, in some cases it may show active tasks
// for other users as the same task may be divided between
// users, like i start the task and you continue it, so for
// the records, user 1 and 2 are involved in the same task.
// The elseif conditions are to extract the info related
// to the current $user so if no condition apply i need
// to change function to return only unnasigned tasks.
// so the i need the first section of the elseif with the
// same conditions of the second section, that is where i
// actually take actions, just to be able to change of
// change of function in case no condition apply and insert
// tasks that are unassigned.
if ($row_task['condition1'] == 1 && etc...) {
} else if ($row_task['condition2'] == 1 && etc...) {
} else if ($row_task['condition3'] == 1 && etc...) {
} else if ($row_task['condition4'] == 1 && etc...) {
} else {
// in case no condition found i change function
// and overwrite the variables
$result = tasks($deadline,'');
$row_task = mysql_fetch_array($result);
}
if ($row_task['condition1'] == 1 && etc...) {
// insert into database
} else if ($row_task['condition2'] == 1 && etc...) {
// insert into database
} else if ($row_task['condition3'] == 1 && etc...) {
// insert into database
} else if ($row_task['condition4'] == 1 && etc...) {
} else {
echo 'nothing to insert</br>';
}
}
}
Basically i run the else if block twice just to be able to change of function in case nothing is found in the first loop and be able to allocate records unassigned.
I haven't changed the functionality of your code, but this is definitely a lot cleaner.
The main problem was that your logic for your if/else statements was confused. When you're writing:
if($a == 1){ } else if($b == 1){ } else if($c == 1){ }else{ //do something }
You're saying If a is 1 do nothing, if b is 1 do nothing, if c is 1 do nothing, but if all of those did nothing, do something when you can just say if a is not 1 and b is not 1 and c is not 1, do something.
I wasn't too sure on your second if statements, but generally it's not good to have an if else with no body within it. However, if the "insert into database" comment does the same thing, you can merge the 3 if statements that do the same code.
I hope i've cleared a few things up for you.
Here's what I ended up with:
foreach ($free_slots as $val) { // here i am looping through some time slots
$slot_out = $free_slots[$x][1];
$slot_in = $free_slots[$x][0];
$slot_hours = $slot_out - $slot_in;
// tasks
if ($slot_out != '00:00:00') {
$result = tasks($deadline, $user);
$row_task = mysql_fetch_array($result);
if (!($row_task['condition1'] == 1 || $row_task['condition2'] == 1 || $row_task['condition3'] == 1 || $row_task['condition4'] == 1)) {
$result = tasks($deadline,'');
$row_task = mysql_fetch_array($result);
}
if ($row_task['condition1'] == 1 && etc...) {
// insert into database
} else if ($row_task['condition2'] == 1) {
// insert into database
} else if ($row_task['condition3'] == 1) {
// insert into database
} else if ($row_task['condition4'] == 1) {
} else {
echo 'nothing to insert</br>';
}
}
}

Working with multiple rows from a MySQL query

Before I begin, I want to point out that I can solve my problem. I've rehearsed enough in PHP to be able to get a workaround to what I'm trying to do. However I want to make it modular; without going too much into detail to further confuse my problem, I will simplify what I am trying to do so that way it does not detract from the purpose of what I'm doing. Keep that in mind.
I am developing a simple CMS to manage a user database and edit their information. It features pagination (which works), and a button to the left that you click to open up a form to edit their information and submit it to the database (which also works).
What does not work is displaying each row from MySQL in a table using a very basic script which I won't get into too much detail on how it works. But it basically does a database query with this:
SELECT * FROM users OFFSET (insert offset here) LIMIT (insert limit here)
Essentially, with pagination, it tells what number to offset, and the limit is how many users to display per page. These are set, defined, and tested to be accurate and they do work. However, I am not too familiar how to handle these results.
Here is an example query on page 2 for this CMS:
SELECT * FROM users OFFSET 10 LIMIT 10
This should return 10 rows, 10 users down in the database. And it does, when I try this command in command prompt, it gives me what I need:
But when I try to handle this data in PHP like this:
<?php
while ($row = $db->query($pagination->get_content(), "row")) {
print_r($row);
}
?>
$db->query method is:
public function query($sql, $type = "assoc") {
$this->last_query = $sql;
$result = mysql_query($sql, $this->connection);
$this->confirm_query($result);
if ($type == "row") {
return mysql_fetch_row($result);
} elseif ($type == "assoc" || true) {
return mysql_fetch_assoc($result);
} elseif ($type == "array") {
return mysql_fetch_array($result);
} elseif ($type == false) {
return $result;
}
}
$pagination->get_content method is:
public function get_content() {
global $db;
$query = $this->base_sql;
if (!isset($_GET["page"])) {
$query .= " LIMIT {$this->default_limit}";
return $query;
} elseif (isset($_GET["page"]) && $_GET["page"] == 1) {
$query .= " LIMIT {$this->default_limit}";
return $query;
} elseif (isset($_GET["page"])) {
$query .= " LIMIT {$this->default_limit}";
$query .= " OFFSET " . (($_GET["page"] * $this->default_limit) - 10);
return $query;
}
}
And my results from the while loop (which should print out each row of the database, no?) gives me the same row everytime, continuously until PHP hits the memory limit/timeout limit.
Forgive me if its something simple. I rarely ever handle database data in this manner. What I want it to do is show the 10 users I requested. Feel free to ask any questions.
AFTER SOME COMMENTS, I'VE DECIDED TO SWITCH TO MYSQLI FUNCTIONS AND IT WORKS
// performs a query, does a number of actions dependant on $type
public function query($sql, $type = false) {
$sql = $this->escape($sql);
if ($result = $this->db->query($sql)) {
if ($type == false) {
return $result;
} elseif ($type == true || "assoc") {
if ($result->num_rows >= 2) {
$array;
$i = 1;
while ($row = $result->fetch_assoc()) {
$array[$i] = $row;
$i++;
}
return $array;
} elseif ($result->num_rows == 1) {
return $result->fetch_assoc();
}
} elseif ($type == "array") {
if ($result->num_rows >= 2) {
$array;
$i = 1;
while ($row = $result->fetch_array()) {
$array[$i] = $row;
$i++;
}
return $array;
} elseif ($result->num_rows == 1) {
return $result->fetch_array();
}
}
} else {
die("There was an error running the query, throwing error: " . $this->db->error);
}
}
Basically, in short, I took my entire database, deleted it, and remade another one based on the OOD mysqli (using the class mysqli) and reformatted it into a class that extends mysqli. A better look at the full script can be found here:
http://pastebin.com/Bc00hESn
And yes, it does what I want it to. It queries multiple rows, and I can handle them however I wish using the very same methods I planned to do them in. Thank you for the help.
I think you should be using mysql_fetch_assoc():
<?php
while ($row = $db->query($pagination->get_content())) {
print_r($row);
}
?>

PHP - else, 'escape' nesting and skip to elseif

I wasn't too sure how to title this question - Here's a snippet of what I'm doing:
<?php
if ($result_rows >= 1 && $membership = 'active') {
if ($when_next_allowed > $today_date) {
$output = 'You cannot renew your membership for another <b>' . $days_left . 'days</b>.';
}
/*
What if the membership is set to active, but it's been over a year since they
activated it? We don't have any server-side functions for determining such
at the time.
*/
else {
/* do database stuff to change the database entry to inactive */
/* skip to elseif below */
}
}
elseif (2 == 2) {
/* create new database entry for user's membership */
}
?>
If the first nested argument is false, it should move onto else which should continue from there and 'escape' the 'parent' if and move onto elseif. Other wise, if the first nested argument is true, then it should stay put.
Is that even a possible occurrence? The only thing I could think of was to add multiple continue; commands. That, of course, threw an error.
One other idea I had was setting a variable to equal continue; within the else, then set that right before the end of the parent if:
if (1 == 1) {
...
else {
$escape = 'continue;';
}
/* $escape here */
}
But I've never heard of, nor do I know of any method of using variables in a 'raw' form like that. Of course I've done research on it, though I've yet to find out how. I'm not sure if that's common knowledge or anything - But I've never heard of, or considered such a thing until now.
Solution? This is something I always thought about, though I never knew I'd have to use it.
Cleanest I could come up with:
$run = false;
if (1 == 1) {
$run = true;
if (1 == 2) {
/* Do something */
} else {
$run = false;
/* Do something else */
}
}
if (!$run && 2 == 2) {
}
Alternatively, you could use a goto between [Do something else] and the 2nd if block, but it'll be messy either way.
if (1 == 1) {
if (1 == 2) {
/* Do something */
} else {
/* Do something else */
goto 1
}
} else if (!$run && 2 == 2) {
1:
}
If I understand the problem correctly, then you could just do something like this:
if (1==1 && 1==2) {
/* ... */
}
elseif (2==2) {
$success = 'Success';
}
Obviously, I don't need to point out that 1==1 && 1==2 is completely illogical and is just used as an example of two boolean statements.
Update based on update to question:
Unless there are additional steps that you are omitting, this replicates your logic. Hard to know if this really solves your problem, because I don't know what 2==2 represents, or what other steps you might need to perform based on what other conditions.
if (($result_rows >= 1 && $membership == 'active') &&
($when_next_allowed > $today_date)) {
$output = 'You cannot renew your membership for another <b>' . $days_left . 'days</b>.';
}
elseif (2 == 2) {
/* create new database entry for user's membership */
}
This should do what you want to do.
If you have a variable to false and switch it to true if you go into the else you want, you just have to test the value of this variable right after to go into elseif you wanted to go in.
<?php
$test = false;
if (1 == 1) {
if (1 == 2) {
/* ... */
}
else {
/* Skip to elseif below */
$test = true;
}
}
if ($test == true) {
$success = 'Success';
}
echo $success;
?>
Not an easy question as it's really hard to understand what you're trying to achieve but I think this is the solution you're looking for.
<?php
$success = False;
if (1 == 1) {
if (1 == 2) {
/* ... */
} else {
$success = True;
/* True case code can go here */
}
}
echo $success;
?>
pseudo code is your friend.
Alternatively;
<?php
$success = False;
if (1 == 1) {
if (1 == 2) {
/* ... */
} else {
$success = True;
}
}
if $success == True {
/* ... */
}
echo $success;
?>
<?php
$continue = false;
if (1 == 1) {
if (1 == 2) {
/* ... */
}
else {
$continue = true;
}
}
if ($continue==true) {
$success = 'Success';
}
echo $success;
?>

Proper way of handling multiple cases

I have a method that can return 3 different cases
public function check_verification_status($user_id) {
global $db;
$sql = "SELECT * FROM `users`
WHERE `id` = ".clean($user_id)."
AND `type_id` = 1";
$result = #mysql_query($sql,$db); check_sql(mysql_error(), $sql, 0);
$list = mysql_fetch_array($result);
if ($list['verification_key'] == '' && !$list['verified']) {
//No key or verified
return 0;
} elseif ($list['verification_key'] != '' && !$list['verified']) {
//key exists but not verified = email sent
return 2;
} elseif ($list['verification_key'] != '' && $list['verified']) {
//verified
return 1;
}
}
A form / message is output depending on the return value from this
I would have used bool for return values when comparing 2 cases, what is the proper way of handling more than 2 cases and what would the ideal return value be.
The way i call this:
$v_status = $ver->check_verification_status($user_id);
if ($v_status === 0) {
//do something
} elseif ($v_status === 1) {
//do something else
} elseif ($v_status === 2) {
//do something totally different
}
I want to learn the right way of handling such cases as I run into them often.
note: I know I need to upgrage to mysqli or PDO, its coming soon
What you have is fine, but you can also use a switch statement:
$v_status = $ver->check_verification_status($user_id);
switch ($v_status) {
case 0: {
//do something
break;
}
case 1: {
//do something else
break;
}
case 2: {
//do something totally different
break;
}
}

Is there a piece of public code available to create a page index using PHP?

I have a MySQL table holding lots of records that i want to give the user access to. I don't want to dump the entire table to the page so i need to break it up into 25 records at a time, so i need a page index. You have probably seen these on other pages, they kind of look like this at the base of the page:
< 1 2 3 4 5 6 7 8 9 >
For example, when the user clicks on the '4' link, the page refreshes and the offset is moved on (4th page x 25 records). Here is what i already have:
function CreatePageIndex($ItemsPerPage, $TotalNumberOfItems, $CurrentOffset, $URL, $URLArguments = array())
{
foreach($URLArguments as $Key => $Value)
{
if($FirstIndexDone == false)
{
$URL .= sprintf("?%s=%s", $Key, $Value);
$FirstIndexDone = true;
}
else
{
$URL .= sprintf("&%s=%s", $Key, $Value);
}
}
Print("<div id=\"ResultsNavigation\">");
Print("Page: ");
Print("<span class=\"Links\">");
$NumberOfPages = ceil($TotalNumberOfItems / $ItemsPerPage);
for($x = 0; $x < $NumberOfPages; $x++)
{
if($x == $CurrentOffset / $ItemsPerPage)
{
Print("<span class=\"Selected\">".($x + 1)." </span>");
}
else
{
if(empty($URLArguments))
{
Print("".($x + 1)." ");
}
else
{
Print("".($x + 1)." ");
}
}
}
Print("</span>");
Print(" (".$TotalNumberOfItems." results)");
Print("</div>");
}
Obviously this piece of code does not create a dynamic index, it just dumps the whole index at the bottom of the page for every page available. What i need is a dynamic solution that only shows the previous 5 pages and next 5 pages (if they exist) along with a >> or something to move ahead 5 or so pages.
Anybody seen an elegant and reusable way of implementing this as i feel i'm re-inventing the wheel? Any help is appreciated.
Zend Framework is becoming a useful collection and includes a Zend_Paginator class, which might be worth a look. Bit of a learning curve and might only be worth it if you want to invest the time in using other classes from the framework.
It's not too hard to roll your own though. Get a total count of records with a COUNT(*) query, then obtain a page of results with a LIMIT clause.
For example, if you want 20 items per page, page 1 would have LIMIT 0,20 while page 2 would be LIMIT 20,20, for example
$count=getTotalItemCount();
$pagesize=20;
$totalpages=ceil($count/$pagesize);
$currentpage=isset($_GET['pg'])?intval($_GET['pg']):1;
$currentpage=min(max($currentpage, 1),$totalpages);
$offset=($currentpage-1)*$pagesize;
$limit="LIMIT $offset,$pagesize";
It's called Pagination:
a few examples:
A nice one without SQL
A long tutorial
Another tutorial
And Another
And of course.. google
How about this jQuery-plugin?
So all the work is done on the clientside.
http://plugins.jquery.com/project/pagination
demo: http://d-scribe.de/webtools/jquery-pagination/demo/demo_options.htm
Heres an old class I dug out that I used to use in PHP. Now I handle most of it in Javascript. The object takes an array (that you are using to split the stack into pages) and return the current view. This can become tedious on giant tables so keep that in mind. I generally use it for paging through small data sets of under 1000 items. It can also optionally generate your jump menu for you.
class pagination {
function pageTotal($resultCount, $splitCount) {
if (is_numeric($resultCount) && is_numeric($splitCount)) {
if ($resultCount > $splitCount) {
$pageAverage = (integer)$resultCount / $splitCount;
$pageTotal = ceil($pageAverage);
return $pageTotal;
} else {
return 1;
}
} else {
return false;
}
}
function pageTotalFromStack($resultArray, $splitCount) {
if (is_numeric($splitCount) && is_array($resultStack)) {
if (count($resultStack) > $splitCount) {
$resultCount = count($resultStack);
$pageAverage = (integer)$resultCount / $splitCount;
$pageTotal = ceil($pageAverage);
return $pageTotal;
} else {
return 1;
}
} else {
return false;
}
}
function makePaginationURL($preURL, $pageTotal, $selected=0, $linkAttr=0, $selectedAttr=0) {
if (!empty($preURL) && $pageTotal >= 1) {
$pageSeed = 1;
$passFlag = 0;
$regLink = '<a href="{url}&p={page}"';
if (is_array($linkAttr)) $regLink .= $this->setAttributes($linkAttr); //set attributes
$regLink .= '>{page}</a>';
$selLink = '<a href="{url}&p={page}"';
if (is_array($selectedAttr)) $selLink .= $this->setAttributes($selectedAttr); //set attributes
$selLink .= '>{page}</a>';
while($pageSeed <= $pageTotal) {
if ($pageSeed == $selected) {
$newPageLink = str_replace('{url}', $preURL, $selLink);
$newPageLink = str_replace('{page}', $pageSeed, $newPageLink);
} else {
$newPageLink = str_replace('{url}', $preURL, $regLink);
$newPageLink = str_replace('{page}', $pageSeed, $newPageLink);
}
if ($passFlag == 0) {
$passFlag = 1;
$linkStack = $newPageLink;
} else {
$linkStack .= ', ' . $newPageLink;
}
$pageSeed++;
}
return $linkStack;
} else {
return false;
}
}
function splitPageArrayStack($stackArray, $chunkSize) {
if (is_array($stackArray) && is_numeric($chunkSize)) {
return $multiArray = array_chunk($stackArray, $chunkSize);
} else {
return false;
}
}
}

Categories