I'm trying to create a user management system class and one of my functions is to check if a value is in a column in the database. It returns nothing at all.
Here is the relevant information:
require("opperators/connect.php");
class UserManagemen
{
protected $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function isInDatabase($checkIfThis, $isHere)
{
$stmt = $db->prepare("SELECT 1 from users WHERE $isHere = :$isHere");
$stmt->execute(array(':$isHere' => $checkIfThis));
if ($stmt->rowCount() > 0) {
echo "It's in the database";
} else {
echo "Not in the database and you are good to go!";
}
}
}
$usermanagement = new UserManagemen($db, null, null, null);
$usermanagement->isInDatabase(Batman, username);
in connect.php: this worked in my procedural coding test.
$configurator['database'] = array(
'username' => 'root',
'password' => 'root',
'host' => 'localhost',
'db' => 'girlscouts',
);
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
);
try {
$db = new PDO("mysql:host={$configurator['database']['host']};dbname={$configurator['database']['db']};charset=utf8", $configurator['database']['username'], $configurator['database']['password'], $options);
}
catch (PDOException $ex) {
die("Failed to connect to the database: " . $ex->getMessage());
}
I apologise in advance if this has been asked repeatedly, I've tried a google but returned nothing of value, possibly because I don't know what to google. I'm not big on asking for help but I'll give it a shot.
I think it should be
if ($stmt->rowCount() > 0) { // data available
echo "It's in the database";
} else {
echo "Not in the database and you are good to go!";
}
instead of
if ($stmt->rowCount() > 0) {
echo "Not in the database and you are good to go!";
} else {
echo "It's in the database";
}
Also you didn't initialize the PDO like new PDO(...);, in your constructor it should be
$this->db = new PDO(...);
and you should use it like
$stmt=$this->db->prepare(...);
$stmt->execute(...);
Take a look at this and this for details.
You are doing it wrong.
Instead of making additional request just to see, if such value already is stored in table, you should set UNIQUE constraint on column. Then, if you have correctly set up the PDO instance, the attempt to insert a duplicate will rise an PDOException, which then you can handle in whichever way you want.
Also the UNIQUE constraint would let you in MySQL perform .. ON DUPLICATE UPDATE .. construction.
To learn more about PDO use, read this tutorial. Seems like you are emulating the prepared statements.
Related
I'm dealing with a PHP application with what seems to have a peculiarity: One of its files (helpers.php) has a couple of functions that includes another file, and the included file (db_connection.php) includes the file that originally included it.
helpers.php:
<?php
function lineBreak()
{
return "\n<br>\n";
}
function saveScoreToDB($score)
{
//session_start(); // Already started
$usuario_id = $_SESSION["usuario_id"];
$etapa = $_SESSION["etapa"];
try
{
$query_etapa = "SELECT id FROM etapas WHERE numero = $etapa";
require_once "db_connection.php";
// `$db_link` works perfectly fine here:
$etapa_id = $db_link->query($query_etapa)->fetchColumn();
$query_score = "INSERT INTO score
(
usuario_id,
etapa_id,
pontos
)
VALUES
(
$usuario_id,
$etapa_id,
$score
)";
$db_link->query($query_score);
}
catch (Exception $e)
{
$_SESSION["error_message"] = $e->getMessage();
header("Location: erro.php");
}
}
function completeTest($redirectTo)
{
unset($_SESSION["etapa"]);
$usuarioId = $_SESSION["usuario_id"];
// TODO: try/catch
try
{
$queryEmailUsuario = "SELECT email FROM usuarios WHERE id = $usuarioId";
$queryNomeUsuario = "SELECT nome FROM usuarios WHERE id = $usuarioId";
require_once "db_connection.php";
// `$db_link` does *not* work here. Why?
$emailUsuario = $db_link->query($queryEmailUsuario)->fetchColumn();
$nomeUsuario = $db_link->query($queryNomeUsuario)->fetchColumn();
// Routine to send email using the variables above
}
catch (Exception $ex)
{
// TODO
}
}
db_connection.php:
<?php
require_once "db_credentials.php";
require_once "helpers.php";
// Variables used here come from `db_credentials.php`
$dsn = "mysql:host=$host;dbname=$dbname;port=3307;charset=utf8;";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
];
try
{
$db_link = new PDO($dsn, $user, $pass, $options);
}
catch (PDOException $e)
{
echo "Error connecting to the database.";
echo lineBreak();
echo $e->getMessage();
echo lineBreak();
echo lineBreak();
}
Notice how in the first script variable $db_link is used in two different functions, both of which include the file where this variable is defined. Within the first function (saveScoreToDB), the variable is available and the function works fine; but within the second (completeTest) it is not available and I get an undefined variable error.
Why is that? How to make it work?
The first require_once() works because that's the "once", but it's only in-scope in that single function call, so $db_link gets tossed out at the end of the function call and is never seen again. You can change that to require(), but creating a new connection for every single function call is... not going to work out well in the long run.
Ideally you create the connection once and then pass it in via parameters where it is needed, eg:
require_once('db_credentials.php');
saveScoreToDB($score, $db_link);
completeTest($redirectTo, $db_link)
But that might get a bit tedious, right? Well this is where classes become useful.
class MyThing {
protected $db;
public function __construct(\PDO $db) {
$this->db = $db;
}
public function saveScoreToDB($score) {
$this->db->prepare(...);
}
public function completeTest($redirectTo) {
$this->db->prepare(...);
}
}
$thing = new Mything($db_link);
$thing->saveScoreToDB(42);
$thing->completeTest('yes');
I'm making a small CMS for some fun and practice. And I've come across this problem where I have to access a database multiple times in different functions. And the way I do it now by making a new prepared statement with the code and all to access the database in the function doesn't seem very convenient since the code is very repetitive and I'm using mostly the same code for each function. So how would I go about creating a class maybe or some functions that reduce the amount of code used in the functions that gather the information from that database? I currently use the following queries in SQL
SELECT
UPDATE
INSERT
DELETE
So mostly the basic ones. The code I'm using is basic PHP code where I'm using prepared statements to access my database like this:
// Create database connection
$con = db_connect();
// Initialize $error variable for errors
$error = "";
if ($stmt = $con->prepare("SELECT * FROM profiles WHERE username = ?")) {
// Bind the $username variable to the parameter in the query
$stmt->bind_param('s', $username);
// Execute the prepared query
$stmt->execute();
$stmt->store_result();
// Assign the data recieved from the database (if any)
$stmt->bind_result($data);
$stmt->fetch();
if ($stmt->num_rows == 1) {
if (!empty($stmt->error)) {
printf("Error: %s.\n", $stmt->error);
return false;
}
// Query successful
} else {
$error .= "User doesn't exist";
return false;
}
} else {
$error .= 'Could not connect to database';
return false;
}
To me this seems like pretty easy to use code, but when you have to paste it again and again in different functions, then it gets a bit frustrating.
You should use Dependency Injection.
By injecting the Database connection into a Profile's class, you have much more maneuverability to do what you please.
You can change that database to whatever you want (MongoDB, Cassandra, MySQL).
You are only declaring the connection once; which performs better and faster
Makes it easier to test and develop (echo & print_r & unit testing)
Handel exceptions in 1 place
Database is loosely couple with rest of code.
ex:
class Profile {
private $db = null;
public function __construct($db Database) {
$this->db = $db;
}
public function getProfile() {
//ish....
$this->db->query("SELECT * FROM profiles WHERE username = ?");
}
public function insert() {
...
}
public function update() {
...
}
public function delete() {
...
}
}
To access the database, I would do something like this and also implement what you have (prepared statements are great!):
class Database {
private $conn = null;
public function __construct($db Database) {
$this->conn = new PDO('mysql:host=localhost;dbname=myDatabase', $username, $password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $this->conn;
}
public function query($sql) {
try {
return $conn->query($sql);
} catch (Exception $e) {
echo $e->getMessage();
}
}
}
A very good explaination and tutorial can be found here: http://code.tutsplus.com/tutorials/dependency-injection-huh--net-26903
I'm rewriting my php code for mysql database access (now using a class definitions). While I had the old code (using old style functions) working I struggle to get the code for creating tables right - I think the problem relates in particular to the right definition of the sql statement, pls see code below. The new aspect (for me) compared to the old code is that the sql table creation command now must include the name of a database different than the master_database for which the PDO connection is set up (within the class constructor).
I looked at http://dev.mysql.com/doc/refman/5.6/en/create-table.html (I use mysql v5.6) - the part starting with "The table name can be specified as db_name.tbl_name to ..." but I cant get the sql syntax right. If I'm right the sql syntax is wrong what should be the right syntax in the code below for $sql (using the construction with various variables)?
Thnx for your help in advance.
Simplified code:
<?php
define('DB_HOST', '***');
define('DB_NAME', 'MASTER_DATABASE'); //different name
define('DB_USER', 'root');
define('DB_PASS', '*****');
//class definitions
class Database {
private $_db = null; //databasehandler
public function __construct() {
try {
$this->_db = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS, array(
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
));
$this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_db->query('SET CHARACTER SET utf8');
} catch (PDOException $e) {
exit('Error while connecting to database.'.$e->getMessage());
}
}
private function printErrorMessage($message) {
echo $message;
}
public function createDBTable($dbname,$dbtable,$tablestructure) {
try {
$sql = "CREATE TABLE `".$dbname."'.'".$dbtable.$tablestructure; //NOT CORRECT YET
$success = $this->_db->exec($sql);
return ($success > 0) ? true:false;
}
catch(PDOException $e){
$this->printErrorMessage($e->getMessage());
}
}
}//class
//code using class defs
$dbname = 'Mydatabase'; //just an existing database
$dbtable = 'Persons';
$tablestructure = '(FirstName CHAR(30),LastName CHAR(30),Age INT)';
$mydb = new Database();
if($mydb->createDBTable($dbname,$dbtable,$tablestructure)){
echo 'table creation success';
}
else{
echo 'table creation failure';
}
?>
You can replace you create table line as:-
$sql = "CREATE TABLE ".$dbname.".".$dbtable."".$tablestructure; //NOT CORRECT YET
Also instead of:-
$success = $this->_db->exec($sql);
Use the below lines:-
$stmt = $this->_db->prepare($sql);
$success = $stmt->execute();
Without the above 2 lines, the $succes variable will have value of 0 and although the table can be created, it would echo table creation failed.
Hope this helps.
So, I'm working on a project that requires a database connection. I've chosen to use PDO for its versatility and need to figure out how to set up the connection. Currently I'm going for something like this:
class Database {
private static $db;
static function initDB() {
if(!is_object(self::$db) || get_class(self::$db) != 'PDO') {
include('core/db.php');
try {
$db = new PDO($database, $username, $password);
} catch(PDOException $e) {
print("<br />Could not establish database connection. Error message: ".$e->getMessage()."<br />");
die();
}
}
//Try the transaction
/*
if($transaction = $db::query(PDO::quote($value)))
$db::query(PDO::quote("INSERT INTO log VALUES ('".Authorization::$user."','".PDO::quote($value)."', 'Success')"));
else
$db::query(PDO::quote("INSERT INTO log VALUES ('".Authorization::$user."','".PDO::quote($value)."', 'Failure')"));*/
}
}
So, this pretty much reveals one of the concepts I don't really know: singletons and static classes/objects. Any way to set up a database connection using OO best practices that initializes with the script via some kind of __construct method?
A database connection should not be either static or a singleton. This merely introduces another form of global state, which is bad for unit-testing and does hide obvious dependencies.
The right way here would be is to inject an instance of PDO into the classes that need it. You adhere the Single-Responsibility Principle and Dependency Injection.
Note, you should never log errors and do include() inside PDOAdapter constructor because its masked violation of the Single-Responsibility Principle
So, this would look like this:
final class PDO_Provider extends PDO
{
/**
* Constructor. Inits PDO
*
* #param array $params
* #return void
*/
public function __construct(array $params)
{
try {
extract($params);
parent::__construct(sprintf('mysql: host=%s; dbname=%s', $host, $database), $user, $password);
$this->setAttribute(parent::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES UTF8');
$this->setAttribute(parent::ATTR_ERRMODE, parent::ERRMODE_EXCEPTION);
$this->setAttribute(parent::ATTR_EMULATE_PREPARES, false);
$this->setAttribute(parent::ATTR_DEFAULT_FETCH_MODE, parent::FETCH_ASSOC);
} catch(PDOException $e) {
die($e->getMessage());
}
}
}
And you would use it like this,
<?php
$sql_config = array(
'host' => 'localhost',
'user' => 'root',
'password' => '',
'database' => '_DB_NAME_',
);
// <- Or you can include that, like
$sql_config = include(__DIR__ . '/core/db_params.php');
$pdoProvider = new PDO_Provider($sql_config);
$user = new User_Login($pdoProvider); // the point here is to inject an instance of $pdoProvider. User_Login is actually irrelevant
if you want to use a normal object instead of sigleton, try something like this:
class PDOConnector{
protected $connection;
function __construct($host, $user, $pass, $db_name)
{
//create database connection
try{
$this->connection = new PDO('mysql:host='.$this->host.';dbname='.$this->db_name.';charset=utf8', $this->user, $this->pass,array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
catch(PDOException $ex) {
echo "An Error occured : ".$ex->getMessage();
}
}
}
This is the function I use to access the DB, theoretically maybe up 10-20 times in a do while loop, though right now I removed the loop so it only can do one db query at a time. Can this be optimized more or is this how transactions and commits are properly done? Also, I don't know what $db->rollBack() actually does, I just saw it on a stackoverflow
<?php
function util_db_access($statement, $array) {
$db = new PDO('mysql:host=localhost;dbname=db;charset=UTF8', 'user', 'pass');
try {
//echo "1";
$db->beginTransaction();
//echo "2";
$stmt = $db->prepare($statement);
//echo "3";
if($stmt->execute($array)) {
$db->commit();
//echo "4";
if($rows = $stmt->fetchAll(PDO::FETCH_ASSOC)) {
//echo "5";
if($stmt->rowCount() < 2) {
$rows = $rows[0];
}
return $rows;
} else {
//echo "6.1";
//$db->commit();
return true;
}
} else {
//echo "6.2";
//$db->commit();
return false;
}
} catch(PDOException $e) {
$db->rollBack();
//log, we are gonna keep a log eventually.. right?
return -1;
}
}
?>
This thing can be optimized very quickly.
For starters you are creating a new connection to the database with every function call. I don't know for sure if the connection is closed when the PDO object goes out of scope but nevertheless it's bad design.
UPDATE
PHP will close the connection to the database when the PDO object is destroyed.
Reference http://php.net/manual/en/pdo.connections.php
Try using a profiler to determine where your bottleneck is - there's one included in xdebug. Given the simplicity of this code, it may be the query itself - try running the query standalone, either using the mysql cli client or MySQL Workbench, and see what timings you get back. If it is the query that's slow, you can use EXPLAIN and the bountiful optimization sections in the MySQL manual to improve it.
$db->rollBack() make a roll back for the transaction. If you don't know what transactions are there is no point for you to use them, because it creates an unnecessary overhead for the server.
commit() permanently writes the data from the query, rollback() undo everything to the state where you called beginTransaction()
Transactions are to be used when its crucial that changes in more then one place happens simultaneously, imagine a transaction of money between two accounts. On simple selects there is absolutely no need for transactions.
(I'm also sceptic to how you use try/catch)
However... If you run one query directly on the db server, is it also slow? Do you open/close the db connection between each call? (if so -(yes)- don't). What is the network relationship between the http/db server?
I can't help rewriting your function, removing useless parts and adding essential ones
function util_db_access($type, $statement, $array) {
static $db;
if (empty($db)) {
$dsn = 'mysql:host=localhost;dbname=db;charset=UTF8';
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
$db = new PDO($dsn, 'user', 'pass', $opt);
}
$stmt = $db->prepare($statement);
$stmt->execute($array);
if($type == 'all') {
return $stmt->fetchAll();
}
if($type == 'row') {
return $stmt->fetch();
}
if($type == 'one') {
return $stmt->fetchColumn();
}
if($type == 'id') {
return $db->lastInsertId();
}
if($type == 'numrows') {
return $stmt->rowCount();
}
}
most likely this new version won't suffer any delays too
now you can use this great function without any delay or inconvenience:
$user = util_db_access("row", "SELECT * FROM users WHERE id = ?", array($someId));
$id = util_db_access("id", "INSERT INTO users SET name=?", array($name));
and so on
However, having just a function for this purpose is quite inconvenient, and I hope you will grow it into class soon. You can take my Safemysql class as a source of some ideas.