I am trying to create a login function that would allow me to specify what table I want to select the data from, and also what fields I want to select.
I have managed to pass the table value to the function, and select data from the desired table, but my tables have different fields. How can I specify in the query it is one table select: user_id, user_first_name, user_password , or if it is the other table select member_id, member_first_name, member_password.
Here is what I have coded so far:
public function logIn($id, $password, $table){
$dataArray = array();
$t = ($table === 'employers') ? 'employers' : 'members');
$query = "SELECT user_id, user_first_name, user_password FROM $t";
$stmt = $this->link->prepare($query);
if ($stmt->execute())
{
$result = $stmt->get_result();
while($row = $result->fetch_array(MYSQLI_ASSOC))
{
$dbuser_id = $row['user_id'];
$dbpassword = $row['user_password'];
$dbuser_first_name = $row['user_first_name'];
}
//and so on...
Also, one quick question: Is this a bad programming practice, or should I have 2 login(members, and users)?
Thanks :)
The Single Responsibility Principle in programming is intended to prevent things like this from happening - the goal is for one class/function to have one responsibility, rather than having to manage 2 (or potentially more) as you have here. In short, it is a bad programming practice and you should have 2 login functions like you said. After making 2 different functions, a switch statement might help to check the case of a member logging in versus a user.
Note: There are exceptions to this. However, in your case, it would make more sense to separate the two.
Here is a link to further explain SRP and SOLID design principles:
Single Responsibility Principle on TutsPlus
Related
I have an over time sheet that gets printed when there is over time from an employee. The overtime format goes like "B.Eng." And then the name of the employee. Now I need it to check the name of the employee (or id) to print either "B.Eng." Or "MR.", This because there is an employee (just one) that does not have a degree. I would think the answer would be an IF condition.
Here is my code:
$db = mysql_select_db ("over_time");
$strqry = "SELECT emp_name FROM contr_acces where id_emp='".$vp_idemp."';";
$qry2 = mysql_query ($strqry);
$row2 = mysql_fetch_object ($qry2);
$vl_emp_name= "B.Eng. ".$row2->emp_name;
print $vl_emp_name;
you can do something like this
$db = mysql_select_db ("over_time");
$strqry = "SELECT emp_name FROM contr_acces where id_emp='".$vp_idemp."';";
$qry2 = mysql_query ($strqry);
$row2 = mysql_fetch_object ($qry2);
$vl_emp_name= $row2->emp_name;
if($vl_emp_name == 'name_without_the_degree){
$vl_emp_name= "Mr. ".$vl_emp_name;
}else{
$vl_emp_name= "B.Eng ".$vl_emp_name;
}
print $vl_emp_name;
It is not the best solution since you are hardcoding the condition but without knowing more about the db structure is not possible to give you a better solution. The most efficient one would be to add a field to the db with the degree type for the users and retrieve it together with the name.
See my comment under your question for the api used and the sql injection risk that this soultion doesn't address
i am doing a mini project of social networking , i am having a doubt about table .
let see , i need to provide post in their page. to do this,should i have to create table for each user or just create one table and use it for multiple users (data can be fetched by selecting particular user name and display it in their page ).
which is the best way?
my php code:
<?php
$query="select * from table_name where user=$username order by time desc;";
?>
To answer your question
It's best to just use 1 table of users and have a separate able for your posts. Your users table should have all the information for each specific users with 1 unique value that is automatically generated by the MySQL database. (Use auto-increment) And in the posts table you should have all the data for each post with a user_id column that holds the unique value from the users table, this way you know who posted it.
Here is a mockup table structure:
Users table:
uid | name | email
Posts table:
uid | user_id | message
user_id in the posts table should always be equal to some uid in the users table.
Every single table should always have some unique value that is assigned its primary value
My real concern
I am very concerned with the security of your application. Prepared statements are WAY easier to use, and WAY more secure.
In the code snippet that you shared:
<?php
$query="select * from table_name where user=$username order by time desc;";
?>
this query is very insecure, as Bobby Tables would tell you. I'm not sure why type of database connection you are using, but I suggest PDO. I wrote a function that makes this very very easy, here is the snippet for that:
This is a file I usually call connection.php that you can import on any page you need to use your database.
<?php
$host = 'localhost';
$db = '';
$user = '';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host={$host};dbname={$db};charset={$charset}";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
function pdoQuery($query, $values = []) {
global $pdo;
if(!empty($values)) {
$stmt = $con->prepare($query);
$stmt->execute($values);
} else {
$stmt = $con->query($query);
}
return $stmt;
}
?>
This function allows you to EASILY use prepared statements by just
including the connection.php page and writing queries in a way that is
readable, clean, and secure. As I'm sure a lot of people reading this are not used to Prepared Statements or know how they
work, the rest of this post will explain that.
One of the biggest differences here is that instead of using String
Interpolation in
your query, you will set variables as question marks ?, so your
query looks like this: UPDATE table SET user=? instead of UPDATE
table SET user='$user' - and the variables will be sent later for
safety, so this prevents SQL Injection.
This it the way your query would look now:
pdoQuery("SELECT * FROM `table_name` WHERE user=? ORDER BY `time` DESC", [$username]);
This is basically how it works:
pdoQuery(string $query, array $variables)
If you pass no variables, it automatically uses the query() function, if you do pass variables it automatically binds and executes the statements. No matter what query you do, the function always returns the query as an object, so you can act on it using any method you can normally use on a PDO query after the execute.
If you know how these work, you can stop reading here :) I put some
exmaples below of some of the ways you can manipulate the return data
to do what you need to do.
This function returns the object of the query you requested, so if you wanted to loop through all of the results of your query you use it like this:
$stmt = pdoQuery("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username])->fetchAll();
foreach($stmt as $row) {
$row['name']."<br>";
}
Or if you just wanted to get a single column from a specific row, you could use it like this:
$username = pdoQuery("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid])->fetchColumn();
Which will return the username from user where uid=$uid as a string
or if you wanted several values from 1 specific row, you could do
$user = pdoQuery("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid])->fetch();
Which will return to $user as an array that has the username, name, and email of the user.
You can also use this function to INSERT, UPDATE, or basically any type of query you can think of. This is how you insert:
pdoQuery("INSERT INTO `table_name` (`name`,`col2`, `col3`) VALUES (?,?,?)", [$name, $col1, $col2]);
My PDO Class
Since writing this post, I have created a new database wrapper class called GrumpyPDO (Hosted on Github).
This class method returns the object of the query you requested, so if you wanted to loop through all of the results of your query you use it like this:
Fetch All
GrumpyPDO Long Syntax
$stmt = $db->run("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username])->fetchAll();
GrumpyPDO Short Syntax
$stmt = $db->all("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username]);
Loop:
foreach($stmt as $row) {
$row['name']."<br>";
}
Single Column Return
Or if you just wanted to get a single column from a specific row, you could use it like this:
//Long Syntax
$username = $db->run("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid])->fetchColumn();
//Short
$username = $db->cell("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid]);
Which will return the username from user where uid=$uid as a string
Entire Row Return
or if you wanted several values from 1 specific row, you could do
//Long Syntax
$user = $db->run("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid])->fetch();
//Short Syntax
$user = $db->row("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid]);
Which will return to $user as an array that has the username, name, and email of the user.
DML Queries
You can also use this function to INSERT, UPDATE, or basically any type of query you can think of. This is how you insert (All DML's are similar):
$db->run("INSERT INTO `table_name` (`name`,`col2`, `col3`) VALUES (?,?,?)", [$name, $col1, $col2]);
There are many questions on SO about this but I cannot find one that quite meets my situation.
I want to use the values in some fields/columns of a table to set the value of a third field/column
In other words something like:
table races
athleteid|difficulty|score|adjustedscore
$sqlSelect = "SELECT athleteid,difficulty,score FROM races";
$res = mysql_query($sqlSelect) or die(mysql_error());
while ($row = mysql_fetch_array($res)){
$adjustedscore=difficulty*score;
$sqlupdate = "UPDATE race, set adjustedscore = '$adjustedscore' WHERE athletes = 'athletes'";
$resupdate = mysql_query($sqlupdate);
}
My understanding, however, is that MYSQL does not support update queries nested in select ones.
Note, I have simplified this slightly. I am actually calculating the score based on a lot of other variables as well--and may join some tables to get other inputs--but this is the basic principal.
Thanks for any suggestions
You can run:
UPDATE `races`
SET `adjustedscore` = `difficulty` * `score`
WHERE `athleteid` IN (1, 2, 3, ...)
First of all, as previous commentators said, you should use PDO instead of mysql_* queries.
Read about PDO here.
When you'll get data from DB with your SELECT query, you'll get array. I recommend you to use fetchAll() from PDO documentation.
So, your goal is to save this data in some variable. Like you did with $row.
After that you'll need to loop over each array and get your data:
foreach($row as $r) {
//We do this to access each of ours athlete data
$adjustedscore= $row[$r]["difficulty"]* $row[$r]["score"];
//Next row is not clear for me...
$query = "UPDATE race SET adjustedscore = '$adjustedscore' WHERE athletes = 'athletes'";
And to update we use PDO update prepared statement
$stmt = $dbh->prepare($query);
$stmt->execute();
}
Here's my issue: I have 3 tables, with overlapping information (specifically, the username) in each. Except the username row isn't named the same thing in every table. Because the username is specific to the user, it makes sense to get all the other information about the user based on the username. Here's what I have. (The first function returns the query, the second function returns the information in an array (or is supposed to, anyway).
function get_user_by_id($id) {
global $connection;
$query = "SELECT * FROM ownerOrganization, owner, queue_acl";
$query .=" WHERE owner.ownerId=ownerOrganization.ownerId";
$query .=" AND owner.ownerId=queue_acl.user_id";
$query .= " AND owner.ownerId ='{$id}'";
$result_set = mysql_query($query);
confirm_query($result_set);
if ($user = mysql_fetch_array($result_set)) {
return $user;
} else {
return NULL;
}
}
function get_user_id() {
if (isset($_GET['ownerId'])) {
return get_user_by_id($_GET['ownerId']);
}
}
But when I do something like, $sel_user = get_user_id(); on another page, it doesn't actually pull up any of the selected users information... I assume that this is happening because my syntax regarding working with multiple tables is incorrect. Anyway, any input would be much appreciated.
To use JOINS, take this snipcode in example :
$query = "SELECT * FROM (ownerOrganization INNER JOIN owner ON owner.ownerId=ownerOrganization.ownerId) INNER JOIN queue_acl ON owner.ownerId=queue_acl.user_id";
$query .=" WHERE owner.ownerId ='{$id}'";
Regards
I was typing what more or less what #MTranchant wrote. I would suggest renaming your columns for easier query authoring and to avoid confusion. For instance your ownerOrganization.ownerid could be named oo_ownerid, and the other columns in the table could follow that naming convention.
Also, have you run the query against the database with a hard-coded $id that you know exists?
Lastly in the query string being sent to the next page, does a ownerId parameter appear that looks like "&ownerId="?
I'm working on a query where I pull data from multiple tables using left joins like this:
$query = "
SELECT
users.name,
users.email,
address.street,
address.city,
address.state,
address.zip
FROM users
LEFT JOIN(
SELECT
addresses.street,
addresses.city,
addresses.state,
addresses.zip,
`addresses.user_id `
FROM addresses
)
AS address
ON users.id = `address.user_id`
WHERE users.id = 1";
$mysql = new mysql(HOST, USER, PASS, DBNAME);
$result = $mysql->query($query)->fetch_object();
The results I get now I can access the results like this:
// get name
$result->name;
//get street address
$result->street;
Since the query will eventually become something a little more complex than that. I would like to be able to access the data like this:
// get user name
$result->user->name;
// get the street address
$result->address->street;
This will help make the data easier to read, since some of the table have similarly named fields.
Any help would be great thanks.
EDIT: (in response to Steve)
I am familiar with ORMs, and I'm currently using the Kohana framework. My interest is in cutting down on the actually number of queries run.
The ORM in the Kohana framework calls a "SELECT *" for each table/model that you call. I'd prefer not to do that if I dont have to.
Running two separate queries(as shown in the example) is not that big of a deal, but in my real example i'll be pulling data from about 10 separate tables, so I'd rather not run separate queries to get the functionality i was describing
To answer your question in the comment, here's the query I would envision:
SELECT
users.name, users.email,
addresses.street, addresses.city, addresses.state, addresses.zip
FROM users
LEFT JOIN addresses
ON users.id = addresses.user_id
WHERE users.id = 1
Since the sub-select is at most a projection of the addresses table, it seems redundant.
As for the main question, I'm having a hard time coming up with anything that's elegant and non-hackish. In fact, the only things that do come to mind are downright ugly. You could, for instance, add prefixes to the column names in the query:
SELECT
users.name AS user_name, users.email AS user_email,
addresses.street AS address_street, ...
You'd have to parse the column names yourself. I suppose it wouldn't be too bad. Something like:
function rowToObject($row) {
$obj = new StdClass();
foreach ($row as $key => $val) {
$keys = explode('_', $key);
$o = $obj;
for ($i=0; count($keys) > 1; ++$i) {
$k = array_shift($keys);
if (! isset($o->{$k})) {
$o->{$k} = new StdClass();
}
$o = $o->{$k};
}
$o->{$keys[0]} = $val;
}
return $obj;
}
...
$result = rowToObject($mysql->query($query)->fetch_assoc());
I think that maybe the only way would be to use some ORM (Object Relational Mapper). Usage of ORM brings other handy stuffs than this, but you have to pay for it whit lower performance.
Good PHP ORMs are e.g. Doctrine or Propel.