I have multiple tables in my database named teacher1, teacher2.... I am trying to access them using a variable $id.
I have written down the following code.
$query = "SELECT * FROM table.$id";
How could i access those different tables using a variable.
I'm not clear from the question text whether your $id variable contains the full table name, or some kind of number.
However, in either case you have to make a slight tweak to your $query variable.
If $id contains the full name of the table (i.e. teacher1):
$query = "SELECT * FROM " . $id;
If $id contains a number used to identify which teacher table it is (i.e. 1, 2, 3, etc):
$query = "SELECT * FROM teacher" . $id;
Learn to use parameters!
$stmt = $conn->prepare($query = "SELECT t.* FROM table t where t.id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
Don't munge query strings with parameter values! This introduces SQL injection risk, can introduce syntax errors that are hard to debug, and can degrade performance.
Related
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]);
This question already has answers here:
How to insert values in a PHP array to a MySQL table?
(2 answers)
Closed 5 years ago.
I'm using PHP session variable to track character ID's between two tables, characters and character_data_store.
The session ID definitely has the correct ID as I have had to print its value before it goes into the mySQL query.
For testing I selected a user I knew had a rapsheet and used
$usersql = "SELECT *
FROM character_data_store
WHERE character_data_store.`key` = 'RapSheet'
AND character_data_store.character_id = '216'";
Obviously I can't use this for all users as I need to confirm the right one has been selected so thats where the session variable comes in.
I've tried using:
$correctPlayer = $_SESSION['selpid'];
echo $correctPlayer; #confirm it's the right id and then remove
$usersql = "SELECT *
FROM character_data_store
WHERE character_data_store.'key' = 'RapSheet'
AND character_data_store.character_id = '$correctPlayer'";
I did some searching on SO and I found that int's need to have double quotes around them not single quotes, I tried that and had no luck but someone else suggested putting the session ID in exactly which I tried next:
$usersql = "SELECT *
FROM character_data_store
WHERE character_data_store.'key' = 'RapSheet'
AND character_data_store.character_id = {$_SESSION['selpid']}";
Each time I do this I get mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given which SO tells me is because this operation results to false, I assume because it's not accepting the playerID from selpid or $correctPlayer?
It definitely works with the testing user where the playerID is inserted directly into the query. But I can't think of a way to do that since I need to match the playerID from table "characters" where the search is done against their first and last name and then pull the rapsheet data against the same playerID in table "character_data_store".
How do I use a variable in the WHERE condition of a MySQL query using a php variable?
You have obvious error in your code. You are missing quotes in {$_SESSION['selpid']} and you are using quotes in column name. Your query should be
$usersql = "SELECT * FROM character_data_store WHERE character_data_store.`key` = 'RapSheet' AND character_data_store.character_id = '{$_SESSION['selpid']}'";
You should not use quotes in column name, instead use backquotes(`) if you really need. I recommend prepared statements.
There are multiple ways to do this. A naive way to do this would be-
$usersql = "SELECT * FROM character_data_store WHERE character_data_store.'key' = 'RapSheet' AND character_data_store.character_id = ".$correctPlayer;
But to avoid sql injections I would recommend you use bindparam function to bind paramaters in a statement.
$sql="SELECT * FROM character_data_store WHERE character_data_store.'key' = 'RapSheet' AND character_data_store.character_id = ?";
if($stmt = $dbh->prepare($sql)){
$stmt->bindParam(1, $correctPlayer, PDO::PARAM_STR);
$ql = $stmt->execute() or die("ERROR: " . implode(":", $dbh->errorInfo()));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$result['data'] = $row;
I am trying to set up PHP queries for MySQL in a way to prevent SQL injection (standard website).
I had a couple of INSERT queries where changing this worked well but on the following SELECT I keep getting an error since the update and it looks like the while loop doesn't work with the changes I made (it works well without using the statement as in the old code).
Can someone tell me what I am doing wrong here ?
New PHP:
$stmt = $conn->prepare("SELECT ? FROM TranslationsMain WHERE location LIKE '%calendar weekday%' ORDER BY sortOrder, ?");
$stmt->bind_param('s', $selectedLang);
$stmt->execute();
$result = $stmt->get_result();
while($arrCalWeekdays = $result->fetch_assoc()){
$calWeekdays[] = $arrCalWeekdays;
}
$conn->close();
Old PHP (changed part):
$sql = "SELECT " . $selectedLang . " FROM TranslationsMain WHERE location LIKE '%calendar weekday%' ORDER BY sortOrder, " . $selectedLang;
$result = $conn->query($sql);
while($arrCalWeekdays = $result->fetch_assoc()){
$calWeekdays[] = $arrCalWeekdays;
}
$conn->close();
Error message:
Fatal error: Call to a member function fetch_assoc() on a non-object in /homepages/21/d580042014/htdocs/myform.php on line 21
Many thanks in advance.
You cannot bind column and table names, only data. You need to specify the table and then bind for your '%calendar weekday%'.
$stmt = $conn->prepare("SELECT " . $selectLang . " FROM `TranslationsMain` WHERE `location` LIKE ? ORDER BY `sortOrder`, " . $selectedLang);
$stmt->bind_param('s', $calendar_weekday);
If you want to use dynamic table / column names you should perform the minimal white-listing of those items. You can build a dynamic white list by asking the database what columns are valid for a given database table. For example:
SELECT `COLUMN_NAME`
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA` = `database_name`
AND `TABLE_NAME` = `table_name`
You could place all of this information in arrays and then check to make sure the table / column names used in the query are in the arrays. Extra consideration for table and column names should be performed, making sure that no key / reserved words are used for these names.
Finally, use backticks around the validated table / column names when calling the values for the dynamic queries. This will cover any potential changes to the key / reserved words list and provides an additional layer of protection.
Is it possible with PHP PDO to use named placeholders that effectively match everything?
Take as example: $sql = "SELECT * FROM users WHERE targetGroup = :targetGroup AND userId = :userId"
And take $statement = $this->dbh->prepare($sql);
Can I then somehow bind values such that I get the following behaviours:
Original query (this can be done obviously).
Parameters: :targetGroup = 1, :userId = 5.
Resulting query: $sql = "SELECT * FROM users WHERE targetGroup = 1 AND userId = 5
A query to show all users
Parameters: Somehow set :targetGroup and :userId to some special value ALL.
Resulting query: $sql = "SELECT * FROM users
I would like to use this such that I can define queries once somewhere in my program, as static strings, and then reuse them to my likings.
You can't do that. You'll have to prepare different statements for different queries.
$findOneStmt = $pdo->prepare("SELECT * FROM user WHERE target_group = :tg AND user_id = :uid");
$findAllStmt = $pdo->prepare("SELECT * FROM users");
Later, when you'll need one of this queries just call:
$findOneStmt->execute(array(':tg' => 123, ':uid' => 321));
$user = $findOneStmt->fetch();
// ...
$findAllStmt->execute();
$users = $findAllStmt->fetchAll();
You could put a conditional in your SQL that lets you show everything. For example:
SELECT *
FROM users
WHERE
1 = :showAll OR (
targetGroup = :targetGroup
AND userId = :userId
)
Then you can set the :showAll to 0 when you want to filter by :targetGroup and :userId or to 1 when you want to ignore :targetGroup and :userId.
I believe best practice however would be to have two separate queries.
The problem is that you're essentially performing two entirely different queries. They may look very similar, but a SELECT * with no where clause is quite different to one with a where clause.
Rather than define SQL queries in one place and then reuse, abstract the functionality out and use that method call as and when needed, it'll provide you with the ability to have the query defined once, but you will have two queries there now. This way is much safer and much better terms of readability and usage.
Alt A below is a statement from a php-mysql tutorial. It works as it should.
I found the id-value rather obfuscated and tested alt B. This also worked!
What is the point with the id-value of alt A?
MySQL 5.0.51, PHP 5.2.6
// Alt A :
$sql = "SELECT * FROM example WHERE id = '".$q."'";
// Alt B :
$sql = "SELECT * FROM example WHERE id = $q";
This are just two different approaches to building a string from static and variable data.
Alternative A uses concatenation, or the joining of string and variable tokens using the concatenation operator.
Alternative B uses variable expansion, wherein the variables inside a double-quote-delimited string are expanded to their values at evaluation time.
Neither is necessarily better or preferred, but if you have to have single-quote-delimited strings, for example, then you would need to use alternative A.
Of course, neither of these is preferable to building SQL queries with bound parameters, as not doing so leaves you vulnerable to SQL injection attacks.
Theres two reasons to use the example in 'Alt A'. First is if the string is enclosed in single quotes '', the variable's name will be used in the string instead of it's value.
$id = 7;
'SELECT * FROM table WHERE id = $id' //works out to: WHERE id = $id
"SELECT * FROM table WHERE id = $id" //works out to: WHERE id = 7
Secondly, it's useful to combine strings with the results of a function call.
"SELECT * FROM table WHERE id = '".getPrimaryId()."'"
Outside of what has already been said I've found it best practice, if I'm writing a query, to write it as so:
$sql = "SELECT * FROM table WHERE uid=" . $uid . " LIMIT 1";
The reason for writing SQL like this is that 1. MySQL query doesn't have to parse the PHP variables in the Query and 2 you now easily read and manage the query.
When PHP communicates with MySQL, it is actually (in essence) two languages communicating with each other. This means that a string will be processed by the first language before being sent to the other. It also means that it is important to think in terms of the receiving language
In this case:
$q = 'some_name';<br/>
$query = "SELECT * FROM exempel WHERE id = $q";<br/>
you are telling MySQL to
"SELECT * FROM example1 WHERE id = some_name.
In this case:
$q = 'some_name';<br/>
$query = "SELECT * FROM exempel WHERE id = '$q'";<br/>
and this case:
$q = 'some_name';<br/>
$query = "SELECT * FROM exempel WHERE id = '".$q."'";<br/>
you are telling MySQL to
"SELECT * FROM example1 WHERE id = 'some_name'.
The first example should cause an error as some_name is not a valid part of a MySQL query (in that context). On the other hand, the next two will work fine, because MySQL will look for the String "some_name".
You can also do this:
$sql="SELECT * FROM exempel WHERE id = {$q}";
which is useful for setting off things like:
$sql="SELECT * FROM exempel WHERE id = {$row[id]}";
in 'alt B', $q must be an int or float or other numeric
in 'alt A', $q can be anything a string, int, etc.
The single quote makes that possible. It's just hard to see sometimes if you are looking at it for the first time.