duplicate return value php - php

$amnt = "1.00";
$from = "USD";
$to = "GBP";
/* Set up new DB object with the from/to currency */
$DBob = new database($from, $to);
$locFrom = $DBob->readLocation($from);
$locTo = $DBob->readLocation($to);
echo $locFrom . $locTo;
The echo return for both objects return the same value, for the $to variable... rather than returning two seperate queries in SQL. The queries are the same however one uses the $from currency code and the other uses the $to currency code
sql code:
public function readLocation($toFrom)
{
//establish a connection to the mysql database
$dbcon = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME) OR DIE ('Could not connect to Mysql database: '. mysqli_connect_error());
if ($toFrom == 'from')
{
//$substring1 = substr($this->fromcurr,0,2);//
$query2 = ("SELECT location AS loc FROM currency WHERE countrycode ="."'$this->fromcurr'");
}
elseif ($toFrom == 'to');
{
//$substring1 = substr($this->tocurr,0,2);//
$query2 = ("SELECT location AS loc FROM currency WHERE countrycode ="."'$this->tocurr'");
}
$result = mysqli_query($dbcon,$query2);
$resultR = mysqli_fetch_array($result);
mysqli_close($dbcon);
$queryResult = $resultR['loc'];
return $queryResult;
}

You have messed up the code of the function so it does not work. I highlight some points how you can improve it which will help you to not only remove the errors but to prevent similar errors in the future by changing how you write your code.
In this discussion, I leave the topic of proper value encoding aside which can result into flaws and defects (SQL inection). Just saying, you should add those on your own.
The main business of the function is to build a conditional SQL query and execute it. So first of all move the query building out of the function into a function of it's own:
private function buildReadLocationSQL($countrycode)
{
$SQLPattern = "SELECT location AS loc FROM currency WHERE countrycode = '%s'";
return sprintf($SQLPattern, $countrycode);
}
Then you need to find out what $countrycode should be. You are using two string values here to describe what you need. Why not name the functions instead?
public function readLocationFrom()
{
...
}
public function readLocationTo()
{
...
}
Having two functions here it's clear what they do and you can not make any mistakes when you invoke (call) them.
The missing part is to encapsulate the database connection and query. This makes sense anyway because you only want to connect to the database once your application runs and not on every query. Connecting to a database is expensive. Also this helps to extend your class later on by making the code more modular.
So let's change the database class a bit to make it store the connection (you don't need to explicitly close it either, PHP will do this for you when the script ends) and to offer a function to query the database:
class Database
{
private $connection;
private function connect()
{
$connection = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($connection === FALSE)
{
throw new RuntimeException(sprintf('Could not connect to Mysql database: %s', mysqli_connect_error()));
}
$this->connection = $connection;
}
private function query($sql)
{
if (!$this->connection) $this->connect(); // lazy connect to the DB
$result = mysqli_query($this->connection, $sql);
if (!$result)
{
throw new RuntimeException(sprintf('Could not query the Mysql database: %s', mysqli_error($this->connection)));
}
return $result;
}
...
}
These two new private functions take care about the database specific connection and query jobs. As you add more and more functions to your database class over time, you can easily re-use them. Also those two are private (as the $connection member), because you want to hide the details from the rest of your application.
This now needs to be brought together with the readLocationFrom and readLocationTo functions to get it to work. As both functions do similar things, we create another private function that encapsulates both and which is similar to your original function logic.
However, this time, we take care that passed arguments contain only values that make sense (pre-condition checks). Also the function is private, so that it can not be called by other code which reduces the possibility of calling it wrong from outside of the class (it can't be called from the outside):
private function readLocationConditional($what)
{
switch($what)
{
case 'from':
$countrycode = $this->fromcurr;
break;
case 'to':
$countrycode = $this->tocurr;
break;
default:
throw new InvalidArgumentException(sprintf('Invalid value for $what ("%s").', $what));
}
$sql = $this->buildReadLocationSQL($countrycode);
$result = $this->query($sql);
$array = mysqli_fetch_array($result);
$field = 'loc';
if (!isset($array[$field]))
{
throw new UnexpectedValueException(sprintf('Row does not contain %s (contains %s)', $field, implode(',', array_keys($array))));
}
$location = $array[$field];
return $location;
}
So let's take a closer look what's done differently to the original function: The input values are validated and the conditional variable is assigned to $countrycode. This helps to keep things apart. In case some "undefined" value for $what is given, an exception is thrown. This will immediately notify you if you used this function wrongly.
Then the new buildReadLocationSQL function is used to create the SQL, the new query function is used to run the query. At the end, the data returned from the database is validated again and an exception is thrown if the needed field is missing. This will immediately notify you if something is wrong with the returned data.
This is now easy to bring together with the two new public functions which are actual wrappers for the new private function readLocationConditional. So let's put this all together:
public function readLocationFrom()
{
return $this->readLocationConditional('from');
}
public function readLocationTo()
{
return $this->readLocationConditional('to');
}
So now, you've rewritten the database class to make it more flexible and better functioning. Put it together and that's it.
The first key point here is that you check error conditions properly. I've used exceptions instead of die because I think it's more developer friendly. You can do this with die statements as well or with error values etc.. But Exceptions do not only tell you a message, but also where something happened, can be caught (you can't catch die) and can have a different type, so they carry much more helpful information if something goes wrong.
The second key point is that you simplify your code. The more simple your code flow is, the easier it is to code. Putting things that cover the same into functions of it's own is very productive. You can write them as you go on while you keep things separated. And another tip: The less parameters a function have (ideally: zero which is not always possible), the less you can do wrong and the less input values you need to verify.
Just to say: You originally did this somehow as well, but not completely. You had only one place where you checked for an error (the connection to the mysql database), but not for the query itself, not for the return value from the query and not for the function parameter. Putting everything into small functions of it's own, it's easier to see what to check for and handle the details.
Last but not least, the new usage, I made the names more speaking (nstd o abbr evrthng):
$amount = "1.00";
$currencyFrom = "USD";
$currencyTo = "GBP";
$db = new Database($currencyFrom, $currencyTo);
echo $db->readLocationFrom(), $db->readLocationTo();
Hope this helps. And don't fear to write some lines of code more as long as it helps to prevent errors (it's your code, use it as a tool for you) and with modularity in mind. In the end you will see that this is less code and less hassles. Looking for the actual part you made an error in is also a good place to start.
Discussion of errors; I've seen the following:
elseif ($toFrom == 'to');
^
If-blocks can be daunting, restructuring your code helps here. Reduce the use of if and especially elseif. Moving parts into functions of it's own helps to reduce complexity. Less complexity, less errors (we are humans).
$query2 = ("...");
^ ^
This parenthesis is superfluous, might be a sign for just copied over code from a previous function call. Take more care.
Just putting the finger on these errors doesn't show the whole picture and just fixing those won't get you a step further. So it's better to recognize the errors and to understand why they have been made and then to think about how to prevent them.

It looks like whatever this code is supposed to do (which isn't entirely clear), it's not being used correctly. Take a look at some important parts:
$from = "USD";
$to = "GBP";
later...
$locFrom = $DBob->readLocation($from);
$locTo = $DBob->readLocation($to);
and inside that function...
if($toFrom == 'from') {
//...
}
else if($toFrom == 'to'); {
//...
}
That conditional is never satisfied. The $toFrom function parameter (which is not a particularly intuitive variable name) is being set to "USD" and "GBP" with the two calls to the function. It's never equal to "from" or "to" as the conditional assumes.
So $query2 never even gets set to anything. This would lead me to believe that the behavior of this line is an error or undefined:
$result = mysqli_query($dbcon,$query2);
Better variable/function names may help lead you to the logical use of whatever this code is supposed to be doing. But as it stands right now, the function is assuming values that the calling code isn't supplying. If the function is going to assume those values, the very first thing it should do is check its input:
if (($toFrom != 'to') &&
($toFrom != 'from')) {
// Incorrect argument(s) supplied.
// Throw an error and do not proceed with the function
}

Related

Php postgresql error, prepared statement already exists

Am getting an error of prepared statement "my_query7" already exists, i call this function each time a user tries to update table leader_info in the database, i have gone through the documentation for pg_prepare and i don't understand what is meant by it should only be run once. code snippets will be of help. Thanks.
function add_leader_country($user_id,$l_country)
{
global $connection;
$query = pg_prepare($connection,"my_query7","update leader_info set l_country = $1 where user_id = $2 and status < 9");
$result = pg_execute($connection,"my_query7",array($l_country,$user_id));
if(!$result)
{
echo pg_last_error($connection);
}
else
{
echo "Records created successfully\n";
}
$row = pg_affected_rows($result);
return $row;
}
Prepare execute does not permit duplicate naming, so that is your error.
A query should only be prepared once, for example, in a cycle for the preparation state must be set out of the for and its execution in the for.
$result=$pg_prepare($connection,"my_query7",$query);
for($id=1;$id<3;$id++){
$result=pg_execute($connection,"my_query7",array($l_country,$user_id));
...
}
In your case using a functio that use the prepare and execute multiple times it's a problem.
What are you trying to accomplish with this function dispatches more code like where you are calling the function. This way I might be able to help you.
If you want to use functions I would use this method
Exemple from https://secure.php.net
<?php
function requestToDB($connection,$request){
if(!$result=pg_query($connection,$request)){
return False;
}
$combined=array();
while ($row = pg_fetch_assoc($result)) {
$combined[]=$row;
}
return $combined;
}
?>
<?php
$conn = pg_pconnect("dbname=mydatabase");
$results=requestToDB($connect,"select * from mytable");
//You can now access a "cell" of your table like this:
$rownumber=0;
$columname="mycolumn";
$mycell=$results[$rownumber][$columname];
var_dump($mycell);
If you whant to use preaper and execute functions try to create a function that creates the preparations only once in a session. Do not forget to give different names so that the same error does not occur. I tried to find something of the genre and did not find. If you find a form presented here for others to learn. If in the meantime I find a way I present it.

Querying database inside of PHP class?

so this is very simple.
Essentially, I'd like to connect the following class:
class mailManager{
function add($address){
$check = $db->query("SELECT * FROM mail_list WHERE email = '$address'");
$exist = mysqli_num_rows($check);
if($exist > 0){
return "Whoops! Your email is already registered with us.";
}else{
if($insert = $db->query("INSERT INTO mail_list (email, datetime) VALUES ('$address', DATE)")){
return "Success! You've joined the CSGO Earn family.";
} else {
return "Aw snap! There was a database communication error. Please try later.";
}
}
}
}
to the database.
However, nothing 'obvious' that I try seems to work and a google search has yielded no results that I can understand. Perhaps somebody could explain it simply for me?
Note: The SQL is there, but it doesn't do anything (obviously).
Regards
Your class does not have immediate access to your $db. You can do this a few different ways.
1) Pass $db into your public function __construct($db) and assign it to a class member like private $db; (most useful)
You then access it like $check = $this->db->query("..etc..");
2) Pass it in via a parameter to the add() function like so:
public function add($address, $db) {
}
3) Bring it in as a global variable: (easiest)
function add($address){
global $db;
$check = $db->query("SELECT * FROM mail_list WHERE email = '$address'");
/*
etc....
*/
}
I'd recommend learning how to do the first one as it will come in very handy when you have a number of database calls within your class.
Two more things regarding your code in the function.
1) You should use NOW() instead of DATE.
2) Since you are using the OOP implementation of mysqli, you should change mysqli_num_rows($check); to $check->num_rows();. I'm not sure if it will work the way you have it, but even if it does it's good practice to treat your objects uniformly.

PHP OOP Help - Work In Progress

I am right now trying to write a PHP class that executes database information. Yet I feel like I am doing something majorly wrong! It seems like what you would have to type in to get it to work is too much. Here is a example of what it looks like:
<?php
class database {
public $query_type = "";
public $database_name = "";
public $database_items_query = array();
public $database_where = "";
public function __construct($query_type, $database_name, $database_items_query, $database_where) {
$this->query_type = $query_type;
$this->query_name = $query_name;
$this->query_items_query = $query_items_query;
$this->query_where = $query_where;
}
public function database_query($query_type, $database_name, $database_items_query, $database_where) {
if ($query_type == "select") {
return $sqlquery = "SELECT ($database_items_query) FROM $database_name WHERE $database_where";
}
elseif ($query_type == "update") {
return $sqlquery = "UPDATE $databasename ";
}
}
}
$username = new database("");
?>
So for the beginning you would have to type in just this to get it to work the first function?
$username = new database("select","users","username","id");
So basically with what I have so far, what am I doing wrong? Sorry if this does not make sense :(
Ok I can see what you are trying to do, A constructor is normally used to "Create" a object. When the object is created then you have the opportunity to store values inside it so you dont have to
re-enter them, You only have to call a constructor once in a objects lifetime, and you can reuse all the methods multiple times.
soo... if you change your method declaration for database_query to something along these lines:
public function database_query($database_items_query = $this->database_items_query, $database_where = $this->query_where) {
$query_type = $this->query_type;
$database_name = $this->database_name;
Then you would be using the class variables as default values so your code would be something along the lines of
$columns = array("Name","Description");
$db = new database("SELECT","my_db",$columns,"1=1");
$db->database_query(); // returns name and description from all rows
$db->database_query(array("*") ); // returns all columns and rows
$db->database_query(array("*"),"id=7"); // returns all columns where id = 7
$other_db = new database("SELECT","my_other_db",$columns,"1=1");
$db->database_query(array("id") ); // calling database_query on first object instance
$other_db->database_query(array("*") ); // calling database_query on second object instance
When using objects/classes you have to remember that you can declare variables which belong to a given instance of the object so you can re
Dunno about you but when I was your age I was writing a fair bit of C, and to get introduced to OO I was described classes as being structs with function pointers inside.
If trying to learn OO I would reccomend taking a look at java since there is a lot of first principals OO stuff out there, then once comfortable with that style of code
taking what you have learned across to the language which you know a bit better (in your case PHP.)

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)

Can I get feedback on this PHP function that tests if a user has signed up?

I'm just getting started on writing functions instead of writing everything inline. Is this how a reusable function is typically written?
function test_user($user) {
$conn = get_db_conn();
$res = mysql_query("SELECT * FROM users WHERE uid = $user");
$row = mysql_fetch_assoc($res);
if (count($row) == 1) {
return true;
}
else {
return false;
}
}
When someone logs in, I have their UID. I want to see if that's in the DB already. It's basic logic will be used in a
"If exists, display preferences, if !exists, display signup box" sort of flow. Obviously it's dependent on how it's used in the rest of the code, but will this work as advertised and have I fallen for any pitfalls? Thanks!
Try this:
$conn = get_db_conn(); # should reuse a connection if it exists
# Have MySQL count the rows, instead of fetching a list (also prevent injection)
$res = mysql_query(sprintf("SELECT COUNT(*) FROM users WHERE uid=%d", $user));
# if the query fails
if (!$res) return false;
# explode the result
list($count) = mysql_fetch_row($res);
return ($count === '1');
Thoughts:
You'll want better handling of a failed query, since return false means the user doesn't already exist.
Use the database to count, it'll be faster.
I'm assuming uid is an integer in the sprintf statement. This is now safe for user input.
If you have an if statement that looks like if (something) { true } else { false } you should collapse it to just return something.
HTH
That is reuseable, yes. You may want to consider moving the SQL out of the PHP code itself.
Although you weren't asking for optimization necessarily, you might want to consider querying for the user's display preferences (which I assume are stored in the DB) and if it comes back empty, display the signup box. You'll save a trip to the database and depending on your traffic, that could be huge. If you decide to keep this implementation, I would suggest only selecting one column from the database in your SELECT. As long as you don't care about the data, there's no reason to fetch every single column.
First off, you need to call
$user = mysql_real_escape_string($user);
because there's an sql injection bug in your code, see the manual. Second, you can simplify your logic by changing your query to:
SELECT COUNT(1) FROM user WHERE uid = $user;
which just lets you evaluate a single return value from $row. Last thing, once you have the basics of php down, consider looking at a php framework. They can cause you trouble and won't make you write good code, but they likely will save you a lot of work.
Indent!
Overall it looks not bad...check the comments..
function test_user($user)
{
$conn = get_db_conn(); //this should be done only once. Maybe somewhere else...?
$res = mysql_query("SELECT uid FROM users WHERE uid = $user");
$row = mysql_fetch_assoc($res);
//I can't remember...can you return count($row) and have that forced to boolean ala C? It would reduce lines of code and make it easier to read.
if (count($row) == 1) {
return true;
}
else {
return false;
}
}
Also,
if (condition) {
return true;
}
else {
return false;
}
can be rewritten as:
return condition;
which saves quite a bit of typing and reading :)

Categories