PDO with table prefix - php

I have the follow Model class, which all my models extends.
class Model {
[...]
protected static $_query; // Query preparated
public function prepare($query = null) {
[...] // Connect to PDO, bla bla bla
self::$_query = self::$link->prepare($query);
}
[...]
}
class Login extends Model {
public function getUser($username = null) {
self::prepare('SELECT * FROM usuarios WHERE usuario = :username LIMIT 1');
self::bindValue('username', $username);
return self::fetch();
}
}
The problem is, I need to insert prefix to my mysql, to avoid table conflicts, but don't want to edit all my querys.
clientone_tablename
clienttwo_tablename
clientthree_tablename
How I can do this, parse and insert table prefix when prepare the query?
I have not tried nothing because what I know is, extend my custom PDO to PHP PDO class, which is not much now..
I have seen this: PDO - Working with table prefixes. But don't worked propertly..
Thanks!

So i've assume you have only 1 MySQL database (minimum package on your webhost) and need to store a copy of a system for each of your clients.
What I was suggesting, is that you create a separate set of tables as you already are (for each client), but the name wont matter because you have a look-up of the table names in your clients table.
Heres my example for you: The clients table should store the table names of their own tables
(e.g. users_tbl = clientone_users for client id:1) So that later on you can just query the clients table and get his/her table names, then use that result to query on his/her user, news, pages, and files tables.
# SQL: new table structure
-- store the names of the clients tables here
CREATE TABLE clients(
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
name VARCHAR(50),
address VARCHAR(250),
email VARCHAR(50),
pass BLOB,
/* table names*/
users_tbl VARCHAR(70),
news_tbl VARCHAR(70),
pages_tbl VARCHAR(70),
files_tbl VARCHAR(70)
) ENGINE = InnoDB;
# PHP: Some definitions for the table structure
$tbl_names = array("_users","_news","_pages","_files");
$tbl_fields = array();
$tbl_fields[0] = array("id INT","users_col1 VARCHAR(10)","users_col2 VARCHAR(20)");
$tbl_fields[1] = array("id INT","news_col1 DATE",...);
$tbl_fields[2] = array(...);
$tbl_fields[3] = array(...);
// refers to YOUR clients table field names (see above)
$clients_fields = array("users_tbl", "news_tbl", "pages_tbl", "files_tbl");
# PHP: Create a user and create the users database
function createUser($name, $address, $email, $pass, $salt) {
global $db, $tbl_names, $tbl_fields;
$success = false;
if ($db->beginTransaction()) {
$sql = "INSERT INTO clients(name, address, email, pass)
VALUES (?, ?, ?, AES_ENCRYPT(?, ?));"
$query = $db->prepare($sql);
$query->execute(array($name, $address, $email, $pass, $salt));
if ($query->rowCount() == 1) { # if rowCount() doesn't work
# get the client ID # there are alternative ways
$client_id = $db->lastInsertId();
for ($i=0; $i<sizeof($tbl_names); $i++) {
$client_tbl_name = $name . $tbl_names[$i];
$sql = "CREATE TABLE " . $client_tbl_name . "("
. implode(',', $tbl_fields[$i]) . ");";
if (!$db->query($sql)) {
$db->rollBack();
return false;
} else {
$sql = "UPDATE clients SET ".clients_fields[$i]."=? "
."WHERE id=?;";
$query = $db->prepare($sql);
if (!$query->execute(
array($client_tbl_name, (int)$client_id)
)) {
$db->rollBack();
return false;
}
}
}
$db->commit();
$success = true;
}
if (!$success) $db->rollBack();
}
return $success;
}
# PHP: Get the Client's table names
function getClientsTableNames($client_id) {
$sql = "SELECT (users_tbl, news_tbl, pages_tbl, files_tbl)
FROM clients WHERE id=?;";
$query = $db->prepare($sql);
if ($query->execute(array((int)$client_id)))
return $query->fetchAll();
else
return null;
}
# PHP: Use the table name to query it
function getClientsTable($client_id, $table_no) {
$table_names = getClientsTableNames($client_id);
if ($table_names != null && isset($table_names[$table_no])) {
$sql = "SELECT * FROM ".$table_names[$table_no].";";
$query = $db->prepare($sql);
if ($query->execute(array((int)$client_id)))
return $query->fetchAll();
}
return null;
}

Just rewrite your queries to use a table prefix found in a variable somewhere. Parsing all your queries for tablenames is more trouble than it is worth. (Do you really want to write an SQL parser?)

Related

Creating an SQL Query based on data from an Array

I'm trying to find a way to simplify an existing function which communicated with our database. The function currently has several parameters (upwards of 15), and everytime a record is added or updated, all the parameters are required.
I have the following PHP Function (simplified):
function addSomethingToDB($var1, $var2, $var3, $var4...) {
# Do SQL Injection checks
...
$query = 'INSERT INTO `table` (`var1`,`var2`,`var3`,`var4`) VALUES ($var1, $var2, $var3, $var4)';
# OR
$stmt = $db->prepare('INSERT INTO `table` (`var1`,`var2`,`var3`,`var4`) VALUES (?,?,?,?)');
$stmt->bind_param('ssss', $var1, $var2, $var3, $var4);
}
The above code obviously gets pretty messy if you have more than a few variables. And it's difficult to work with if not all variables are required. Because of this I attempted a second scenario where I either had one main/required parameter followed by an array or I just had an array as the parameter.
function addSomethingToDB($var1, array $attributes) {}
The goal here was to allow the array to have a more flexible approach in case the SQL query either needs to be extended in the future, or to build the SQL query based on optional values.
For example:
If Var2 and Var4 are not provided, the array would look like:
{
'var1': 'Var1_Value',
'var3': 'Var3_Value'
}
and the SQL would be:
$query = 'INSERT INTO `table` (`var1`,`var3`) VALUES ($var1, $var3);
As you can see, in the above scenario, the query was adapted for only the necessary values.
What I want to try and achieve is to build the SQL query based on the values provided. The first was I assume would be to have an IF ELSE statement or a SWITCH. Which gives me something weird like the following:
function getlogs($type, $id='') {
$types = array('client_log', 'system_log', 'user_log', 'api_log', 'project_log', 'lead_log');
if (in_array($type, $types)) {
if ('client_log' == $type) {
if (!empty($id)) {
$query = 'SELECT * FROM `logs` WHERE `client_id` = ' . $id . ' AND `type` = "client_log"';
} else {
$query = 'SELECT * FROM `logs` WHERE `type` = "client_log"';
}
} elseif ('project_log' == $type) {
if (!empty($id)) {
$query = 'SELECT * FROM `logs` WHERE `project_id` = ' . $id . ' AND `type` = "project_log"';
} else {
$query = 'SELECT * FROM `logs` WHERE `type` = "project_log"';
}
} elseif ('user_log' == $type) {
if (!empty($id)) {
$query = 'SELECT * FROM `logs` WHERE `staff_id` = ' . $id . ' AND `type` = "staff_log"';
} else {
$query = 'SELECT * FROM `logs` WHERE `type` = "staff_log"';
}
} elseif ('lead_log' == $type) {
if (!empty($id)) {
$query = 'SELECT * FROM `logs` WHERE `client_id` = ' . $id . ' AND `type` = "lead_log"';
} else {
$query = 'SELECT * FROM `logs` WHERE `type` = "lead_log"';
}
} else {
$query = 'SELECT * FROM `logs` WHERE `type` = ' . $type;
}
$logs = Config::$db->query($query);
return $logs->fetch_all(MYSQLI_ASSOC);
} else {
return 'invalid log type';
}
$stmt->close();
}
The above is not quite the code I want to be writing, it's a similar example where the query related to the Log Type is being called. But that is a lot of mess that is not pleasing to look at. Also, the above code does not use Arrays which is what I hope to be using.
Lastly, the code I am hoping to write is mostly related to Updating existing records. So, say we have a User. The user has an Email and a Password and Address. According to the above code (first one) we will be updating the Email, Password, and Address every time the user updates any one of his field. I would like to avoid that.
My assumption is that I'd have to do something like so:
# 1. Loop Array using maybe For or Foreach
# 2. Have a whitelisted array of allowed values.
# 3. Append to query if an Array value exists.
# 4. Run query.
I fear my problem is at Point 3. I can't seem to figure out how to build the query without going through a lot of messy IF ELSE statements.
Now, by this point, I have certainly searched around SO to find a similar question, however, searches related to SQL and Arrays are almost entirely related to adding "multiple rows in a single SQL query" or something similar.
You can approach this by using arrays, in which keys are column name and containing the values
$columns = [
'field1' => 'value1',
'field2' => 'value2',
'field3' => 'value3',
'field4' => 'value4'
];
addSomethingToDB($columns);
function addSomethingToDB($cols){
# Do SQL Injection checks
$query = "INSER INTO `tablename` ( ".implode(",",array_keys($cols))." ) VALUES ( '".implode("','",array_values($cols))."' )";
}

Function/Trigger already in use?

Im having problems getting an update function to work. The function marks badges as seen so that they are hidden from a notification window.
The function is called when the user clicks a button to mark them as seen.
I have two triggers on the table its trying to update which I think may be causing the problem.
The problem is : Can't update table 'users' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Triggers:
Function:
function markAsSeen() {
require "connect.php";
$seen = mysqli_query($connection,"Update userbadges
INNER JOIN users ON users.id = userbadges.user_id
SET seen='1'
WHERE studentid = '".$_SESSION["studentid"]."' && seen=0") or die(mysqli_error($connection));
while ($data = mysqli_fetch_array($seen)) {
echo 'Done';
}
}
Is there any way around this?
Your issue is that the update_users_trigger trigger makes changes to the contents of the table users, while the query that is triggering the execution of this trigger also uses the table users.
You will need to adjust your query so that this deadlock doesn't occur. It isn't clear which fields are from each table, but I suspect that in your initial query you need to join on users so that you can query on studentid.
You could create a different function to get the userID that you need something like the following:
require_once "connect.php";
function getUserIDFromStudentID($student_id, mysqli $connection)
{
$query = 'SELECT id FROM users WHERE studentid = ? LIMIT 1';
$stmt = $connection->prepare($query);
// Replace the below s to an i if it's supposed to be an integer
$stmt->bind_param("s", $student_id);
$stmt->execute();
$result = $stmt->get_result();
$record = $result->fetch_object();
$result->free();
if ($record) {
return $record->id;
}
}
function markAsSeen(mysqli $connection) {
$user_id = getUserIDFromStudentID($_SESSION["studentid"], $connection);
if (! $user_id) {
throw new Exception('Unable to get user id');
}
$seen_query = 'UPDATE userbadges SET seen = 1 WHERE user_id = ? and seen = 0';
$stmt = $connection->prepare($seen_query);
// Replace the below s to an i if it's supposed to be an integer
$stmt->bind_param("s", $user_id);
$result = $stmt->execute();
if (! $result) {
die(mysqli_error($connection));
}
echo 'Done';
}
Passing the connection object around rather than requiring a global file to be required every time will allow for more flexibility.

MySql Query - Check for data if it is exist, if yes get the id, if not, add the data and get the id

I can do it with php/mysqli with multiple step.
So, table have only two column.
ID, Name
Both of then will be unique.
I want to check if Name is available in the database, get the ID if it is available.
If it is not available, add Name on the database and get the ID.
I can do it with php/mysql which need multiple sql query.
Is there a way do it (checking database, if not exist add it and get the ID) only with one mysql query and get the ID?
Thanks in advance!
My code (MySQLi Procedural)
function abc($name) {
global $conn;
$checkName = mysqli_query($con,"SELECT * FROM category WHERE name=".mysql_real_escape_string($name));
if (mysqli_num_rows($checkName) > 0) {
$inputName = mysqli_query($con,"INSERT INTO category (name) VALUES ('".mysql_real_escape_string($name)."')");
if (!$inputName) { die(mysqli_error($conn)); }
$checkName2 = mysqli_query($con,"SELECT * FROM category WHERE name=".mysql_real_escape_string($name));
while($blahblah = mysqli_fetch_assoc($checkName2)) {
$returnData[] = $blahblah;
}
} else {
while($blahblah = mysqli_fetch_assoc($checkName)) {
$returnData[] = $blahblah;
}
}
return $blahblah;
}
This can be done with just one line. Use "INSERT IGNORE INTO.." or "REPLACE INTO....". This page refers.
If you use the Object-Oriented MySQLi, this is how you do it:
$mysqli = new mysqli(...);
$name = "Something";
$query = $mysqli->prepare("SELECT id, name FROM table WHERE name=?");
$query->bind_param('s', $something);
$query->execute();
$query->bind_result($id, $name);
$query->store_result();
if($query->num_rows == 1) {
return $id;
} else {
$queryTwo = $this->mysqli->prepare("INSERT INTO table VALUES('', ?);");
$queryTwo->bind_param('s', $name);
$queryTwo->execute();
$queryTwo->close();
$queryThree = $this->mysqli->prepare("SELECT id FROM table WHERE name=?");
$queryThree->bind_param('s', $name);
$queryThree->execute();
$queryThree->bind_result($id);
$queryThree->store_result();
while($queryThree->fetch()) {
return $id;
}
$queryThree->free_result();
$queryThree->close();
}
$query->free_result();
$query->close();

Updating a form entry in php/mysql with checkboxes?

How can I allow the user submitting a form, to update his entry on "re-submission"
for example
12345678910 (unique id) , submitted the form with selections,
12345678910 , re-submitted with new selections
what's the function responsible for "automatically" updating such kind of form entries.
I know that I can use a check if the entry exists, but how do I update it if it exists and insert it in a new row if it doesn't ...
function checkstudentid($studentid)
{
$con = connectvar();
mysql_select_db("database1", $con);
$result = mysql_query(
"SELECT * FROM table WHERE studentid='$studentid' LIMIT 1");
if(mysql_fetch_array($result) !== false)
....
// I want to add the entry here since it doesn't exist...with checkboxes
// else , I want to update if it already exists
}
Now I'm also not completely positive if the above code will work...but this is what I have for starters, if there is any other way or if the method I'm using is "wrong" , I would appreciate the heads up...or if what I'm trying to is even possible (the way I'm doing it)...
NOTES
I only have one php file which the form submits to.
I am not using a login/registration system
I do not want to display all the data in a table using HTML, just an
"automatic" update if the studentid already exists in the table
If I were using a deprecated method to interact with a database, I would probably just do this:
<?php
function checkstudentid($studentid) {
$con = connectvar();
mysql_select_db("database1", $con);
$result = mysql_query(
"SELECT * FROM table WHERE studentid='$studentid' LIMIT 1");
$query = '';
if (mysql_num_rows($result) > 0) {
$query = "UPDATE table SET column1='$value_one', column2='$value_two' WHERE studentid='$studentid'";
} else {
$query = "INSERT INTO table VALUES('$new_id', '$value_one', '$value_two')";
}
if (mysql_query($query)) {
return true;
} else {
return false;
}
}
?>
But then again, I would use PDO to interact with the DB.
Here is a simple PDO example (you just have to write the function to return the connection):
<?php
function checkstudentid($studentid) {
$update = false;
$dbh = formPDOConnection();
$query = "SELECT studentid FROM table WHERE studentid=:id";
$stmt = $dbh->prepare($query);
$stmt->bindValue(':id', $studentid, PDO::PARAM_STR);
if ($stmt->execute()) {
if ($stmt->rowCount()) {
$update = true;
}
} else {
return 'failure to execute query';
}
// if we just need to update
if ($update) {
$update = "UPDATE table SET value1=:v1,
value2=:v2 WHERE studentid=:id";
$stmt = $dbh->prepare($update);
$stmt->bindValue(':id', $studentid, PDO::PARAM_STR);
$stmt->bindValue(':v1', $value_one, PDO::PARAM_STR);
$stmt->bindValue(':v2', $value_two, PDO::PARAM_STR);
} else {
$insert = "INSERT INTO table VALUES(:id,:v1,v2)";
$stmt = $dbh->prepare($insert);
$stmt->bindValue(':id', $new_id, PDO::PARAM_STR);
$stmt->bindValue(':v1', $value_one, PDO::PARAM_STR);
$stmt->bindValue(':v2', $value_two, PDO::PARAM_STR);
}
return $stmt->execute();
}
?>
Save yourself a headache and stop using mysql_*
You can use INSERT... ON DUPLICATE KEY UPDATE... on your mysql code instead use the logic in your PHP.
Here's a sample:
INSERT INTO `category` (`id`, `name`) VALUES (12, 'color')
ON DUPLICATE KEY UPDATE `name` = 'color';
Reference: http://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html

INSERT & CREATE TABLE doesn't seem to be working

I'm currently experiencing some problems.
Basically, I use PDO and I want to create a table and insert some stuff into the table.
I've tried searching for solutions, but it doesn't seem like anything is working.
Please take a look at this:
public function install()
{
global $con;
$sql = "CREATE TABLE if not exists users
(id INT(11) PRIMARY_KEY,
uname VARCHAR(30) ,
pass VARCHAR (40))";
$sq = $con->query($sql);
if ($sq)
{
echo "Table successfully created!";
}
else
{
$this->errors[] = 'Error creating table: users';
}
$sql_code = "INSERT INTO users (
`uname`,
`pass` ) VALUES(
`$this->username`,
`$this->password`
)";
$sq1 = $con->query($sql_code);
if ($sql_code)
{
echo "Successfull!";
}
else
{
echo "Error creating admin user!";
}
}
NOTE: The database connection is set in another file called config.php and I've also included the config.php file to the code.
Well, there could be plenty of things going on, perhaps at the same time.
Maybe your database connection is failing (I'd recommend passing the connection $con by reference to the function install rather than using the global keyword).
Maybe you don't have enough rights to create a table in the database.
Also you are not binding your parameters, this would be the correct way to do it:
$sql_code = "
INSERT INTO users (
uname,
pass
)
VALUES (
:userName,
:password
);
";
$sq1 = $con->prepare($sql_code);
$sq1->bindParam(':userName', $userName);
$sq1->bindParam(':password', $password);
$sq1->query($sql_code);

Categories