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.
Related
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.)
after searching for a long time got this great article its really very nice
but i am facing a bit problem here in my stuff as u have used direct mysql query in api i have used stored procedure in here and every time i have to compare two XML before and after even for a single short and sweet query so is there any alternative for this process but which is this secure
please chk this out u will get i more clearly
database testing in php using phpunit,simpletest on api haveing stored procedure
or how shall i compare to xml files before and after api function call(the function contains the stored procedure)
means i am able to get the before state with mysql-dump but the after but not getting the instant after xml state
sorry for the English but tried my best
thanks for the help friend
have to write an unit test test for the api function
public function delete($userId)
{
// this function calls a stored procedure
$sql = "CALL Delete_User_Details(:userId)";
try {
$db = parent::getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam("userId", $userId);
$stmt->execute();
$id = $stmt->fetchObject();
if ($id == null) {
$delete_response->createJSONArray("DATABASE_ERROR",0);
} else {
$delete_response->createJSONArray("SUCCESS",1);
}
} catch (PDOException $e) {
$delete_response->createJSONArray("DATABASE_ERROR",0);
}
return $delete_response->toJSON();
}
i have writen this unit test for it now want to write an dbunit for it
public function testDeleteUser()
{
$decodedResponse = $response->json();
$this->assertEquals($response->getStatusCode(), 200);
$this->assertEquals($decodedResponse['status']['StatusMSG'], 'SUCCESS');
$this->assertEquals($decodedResponse['status']['Code'], '1');
}
help guyss
u can just simply test it before by calling the query like
$sql = "select * from user";
and compare it with BeforeDeleteUser.xml
And the Call Ur stored procedure
$sql = "CALL Delete_User_Details(:userId)";
And for the after case just repeat the before one again
$sql = "select * from user";
and compare it with AfterDeleteUser.xml
see the logic is very simple if u have 5 Users in BeforeDeleteUser.xml and it results true and after the call of CALL Delete_User_Details(:userId) stored procedure , the AfterDeleteUser.xml should contain only 4 user (or maybe idDelete field to 0 that depends on ur implementation)
after reading like 5 hours on Google I can't fix something with MySQLI.
I spent all my life programming in MySQL, and now I am trying to update my knowledge using mysqli but I have some troubles.
I have a little function called news_Default() like this:
<?php
Class Test extends DB{
public function news_Default(){
$query = $this->db->query('SELECT * FROM news');
if($query->num_rows == 0)
return false;
else
return $query->fetch_object();
}
}
?>
And I used in this way:
<?php
while($new = $panel->news_Default()){
print_r($new);
}
?>
In MySQL, when I return the object, I can use it with 'while' or 'foreach' loop without problems, but the real problem is here, with mysqli.
When I used the 'while' (second codeblock), it loops 6,000 times (I used a $counter++ to test it), and when I used foreach, it loops exactly 7 times. In my table called 'news' I have only two records. So, how can I return the object and use it outside without having this problems? Because when I use it inside the class like $new = $query->fetch_object() works perfect.
You are doing sql query every time when you are calling news_Default.
Examle for fixing it.
Class Test extends DB{
private $_cached_news = null; // let's store our query result
public function news_Default(){
if ($this->_cached_news === null){ // not stored?
$this->_cached_news = $this->db->query('SELECT * FROM news');} // let's query
$return = $query->fetch_object(); // get next object
if (!$return) // there is no objects anymore?
$this->_cached_news = null; // let's clear our result
return $return;
}
}
For a plugin system I am writing, I need to write a database API. But I want to restrict database access, so plugins can't see other tables than the ones they created through a specific function. How would I enable plugins to use SQL, but not give them full access at the same time?
Here is some code, it may not be working, but it shows the idea behind it:
class Api_Database {
private $pluginid;
function __construct($pluginid) {
$this->pluginid = $pluginid;
}
function query($sql, $tablename) {
$db = new Sys_Database;
$db->query(str_replace('{table}', $pluginid.$tablename, $sql));
}
}
Am I thinking in the right direction here? How would you create such a system, only more secure?
The idea is to create a table containing the list of created tables linked to the user...
Something like :
privileges
user_id
table_name
And in your query
SELECT FROM privileges WHERE user_id = '{user_id}' and table_name = '{table}';
And after check if the row exist. If yes, the user have the right to use the table!
class Api_Database {
private $pluginid;
function __construct($pluginid) {
$this->pluginid = $pluginid;
}
function query($sql, $tablename) {
$hasPrivilege = $this->checkPrivileges($tablename, $userid);
if(!$hasPrivilege) return false; //for example
$db = new Sys_Database;
$db->query(str_replace('{table}', $pluginid.$tablename, $sql));
}
function checkPrivileges($table, $user_id) {
$db = new Sys_Database;
$result = $db->query('SELECT id FROM privileges WHERE user_id = "'.$user_id.'" AND table_name = "'.$table.'"');
return ($result && $result->num_rows);
}
}
EDIT
So if I understand correctly, you are using a PHP plugin to access SQL data, but you can't or doesn't want to change it.
You cant' add SQL users too, and you wan't to restrict PHP Dev to make some queries in some table via PHP?? Hum... Impossible!
Because to be able to disallow database table access, YOU HAVE TO MANIPULATE PHP OR MYSQL USERS...
Or if I'm wrong, sorry, it's difficult to follow you!
$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
}