Uncaught PDOException for SQLite - unable to open database file - php

I have a php web site with a SQLite database. This code opens and queries the database without error:
use App\SQLiteConnection;
$pdo = (new SQLiteConnection())->connect();
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$stmt = $pdo->query("SELECT empid, fullname FROM employees ORDER BY fullname");
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
$employees[] = [
'empid' => $row['empid'],
'fullname' => $row['fullname']
];
}
This code here:
use App\SQLiteConnection;
$pdo = (new SQLiteConnection())->connect();
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$training_id = $_POST['id'];
$stmt = $pdo->prepare("SELECT description from training WHERE id = :training_id");
$stmt->bindParam(':training_id', $training_id);
$stmt->execute();
echo $stmt->fetchColumn();
gets an error of:
Fatal error: Uncaught PDOException: SQLSTATE[HY000] [14] unable to
open database file in
C:\Bitnami\wampstack-7.3.10-0\apache2\htdocs\arborcircle\app\SQLiteConnection.php:23
Stack trace: 0
C:\Bitnami\wampstack-7.3.10-0\apache2\htdocs\arborcircle\app\SQLiteConnection.php(23):
PDO->__construct('sqlite:db/EmpTr...') 1
C:\Bitnami\wampstack-7.3.10-0\apache2\htdocs\arborcircle\functions\get_training_description.php(10):
App\SQLiteConnection->connect() 2 {main} thrown in
C:\Bitnami\wampstack-7.3.10-0\apache2\htdocs\arborcircle\app\SQLiteConnection.php
on line 23
Here is my SQLiteConnection class:
class SQLiteConnection {
/**
* PDO instance
* #var type
*/
private $pdo;
/**
* return in instance of the PDO object that connects to the SQLite database
* #return \PDO
*/
public function connect() {
if ($this->pdo == null) {
$this->pdo = new \PDO("sqlite:" . Config::PATH_TO_DB_FILE);
}
return $this->pdo;
}
}
Both of the examples of how I am querying the database seems similar to me, but I cannot see why the 2nd example is throwing an error of opening the same database.
Any help appreciated.

Information to consider:
SQLite uses reader/writer locks on the entire database file. That means if any process is reading from any part of the database, all other processes are prevented from writing any other part of the database. Similarly, if any one process is writing to the database, all other processes are prevented from reading any other part of the database. For many situations, this is not a problem. Each application does its database work quickly and moves on, and no lock lasts for more than a few dozen milliseconds. But there are some applications that require more concurrency, and those applications may need to seek a different solution.
Also try to add PDO::ATTR_PERSISTENT => true in your SQLiteConnection class:
public function connect() {
if ($this->pdo == null) {
$this->pdo = new \PDO(
"sqlite:" . Config::PATH_TO_DB_FILE, '', '',
array(
PDO::ATTR_PERSISTENT => true
)
);
}
return $this->pdo;
}

Related

Uncaught TypeError: PDO::__construct() expects parameter 1 to be string

I have searched the forum, but I have not found anything directly related to my issue. I am fairly new to PDOs and class OOP creation. I am trying to create a database connection class where I can instantiate the connection as needed. I having issues instantiating my connection.
File Organization:
parent directory (folder)
|
private (folder)
|
config.php
classes (folder)
|
class1.class.php
DatabaseConnection.class.php
db_cred.inc.php
public (folder)
|
search.php
Process:
I have created a database credential php file "db_cred.inc.php"
I have a database connection class called "DatabaseConnect" in "DatabaseConnect.class.php" file
I load those files as follows
require_once 'db_cred.inc.php'; in the "DatabaseConnect.class.php" file
spl_autoload_register for all of my class files
Expected actions:
When my "search.php" page request data from mysql via a pdo, a new database connection will instantiate a new connection via the "openConnection()" method.
The class "DatabaseConnection" will load the credentials from "db_cred.inc.php" as a sting and connect to the database
The class will then use the credentials to connect to the mysql database, and execute the requested pdo query returning the results and storing them into a variable "$row".
Issue:
When I execute the pdo, the following error is returned:
Uncaught TypeError: PDO::__construct() expects parameter 1 to be string, array given in private/classes/DatabaseConnect.class.php:21 Stack trace: #0 private\classes\DatabaseConnect.class.php(21): PDO->__construct(Array) #1 \public\search.php(53): DatabaseConnect->openConnection() #2 {main} thrown in \private\classes\DatabaseConnect.class.php on line 21
spl_autoload_register() in the config.php file
function my_autoload($class) {
if(preg_match('/\A\w+\Z/', $class)) {
require ('classes/' . $class . '.class.php');
}
}
spl_autoload_register('my_autoload');
Credential setup in "db_cred.inc.php"
<?php
// define an array for db connection.
define("DB", [
"DB_HOST" => "mysql:host=localhost",
"DB_USER" => "user",
"DB_PASS" => "pass",
"DB_DATABASE" => "mytestdb",
"DB_CHAR" => "utf8",
]);
?>
My class for database connection:
<?php
require_once 'db_cred.inc.php';
// creating db connection class
class DatabaseConnect {
private $server = 'DB_HOST';
private $database = 'DB_DATABASE';
private $pass = 'DB_PASS';
private $user = 'DB_USER';
private $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
protected $con;
public function openConnection() {
**ERROR TAKES PLACE HERE**
try {
$this->con = new PDO([$this->server, $this->database, $this->user, $this->pass]);
return $this->con;
} catch(PDOExeption $e){
echo "ERROR: " . $e->getMessage(), (int)$e->getCode();
}
}
public function closeConnection() {
$this->con = null;
}
}
?>
PDO for search.php
<?php
$dbconn = new DatabaseConnect();
$pdo = $dbconn->openConnection();
$sql = "SELECT * FROM report";
foreach ($pdo->query($sql) as $row) {
echo " PI: ".$row['pi'] . "<br>";
}
?>
I am not sure what is causing the error. I am sure it is due to my inexperience with classes and oop. It appears that the config.php file is working fine. The class is identified by the request because the error happens inside the PDO __construct method. Please help.
UPDATE - MY WORKING SOLUTION
I hope this might help someone moving forward with a similar question. I am not finished with the development of this process, but this kicked in a huge door.
My revised class
<?php
// Associating db_cred.inc.php with class
require_once('db_cred.inc.php');
// Creating db connection class
class DatabaseConnect {
/*
!! Assigning defined constants per define('DB_CONSTANT', 'value') loaded from "db_cred.inc.php" file to variables
!! "db_cred.inc.php" should not be loaded into the "config.php" file
!! BECAUSE THE VALUES OF THE VARIABLES ($variable) ARE CONSTANTS (DB_CONSTANT), DO NOT USE SINGLE OR DOUBLE QUOTES. THE PDO __CONSTRUCT FUNCTION WILL IGNORE THE VALUE OF THE VARIABLE
*/
private $host = DB_HOST;
private $database = DB_DATABASE;
private $pass = DB_PASS;
private $user = DB_USER;
private $char = DB_CHAR;
// Setting attributes and storing in variable $opt
private $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
// $con variable will store PDO connection and is set to NULL
private $con;
// Create Connection to database
public function openConnection() {
// Setting $con to null
$this->con = NULL;
// If $con is not NULL make it NULL
if ($this->con === NULL){
try {
// Establish DSN
$dsn = "mysql:host={$this->host};dbname={$this->database};charset={$this->char}";
// Complete the PDO connection
$this->con = new PDO($dsn, $this->user, $this->pass,$this->opt);
// Return the connection and store it in $con
return $this->con;
// Catch any exceptions and store in $e
} catch(PDOExeption $e){
// Echo error and Exception message
echo "ERROR: " . $e->getMessage(), (int)$e->getCode();
}
// If the try/catch block fails, echo that no connection was established
} else {
echo "ERROR: No connection can be established";
}
}
// Close connection and set it to NULL
public function closeConnection() {
if($this->con !== NULL){
$this->con = NULL;
}
}
// create CRUD subclass (Create, Read, Update, Delete)
}
?>
I changed "db_cred.inc.php" eliminating the array. I may revisit the idea.
<?php
// defining DB Credential CONSTANTS to be stored in variables and instantiated by connect class
define("DB_HOST", "localhost");
define("DB_USER", "user");
define("DB_PASS", "pass");
define("DB_DATABASE", "mytestdb");
define("DB_CHAR", "utf8");
// define an array for db connection.
/*define("DB", [
"DB_HOST" => "localhost",
"DB_USER" => "user",
"DB_PASS" => "pass",
"DB_DATABASE" => "mytestdb",
"DB_CHAR" => "utf8",
]);*/
?>
The error explains itself: You're passing an array where you should be using a string instead.
You need to change this line:
$this->con = new PDO([$this->server, $this->database, $this->user, $this->pass]);
To this, (specifies the DSN first):
$dsn = "mysql:dbname={$this->database};host:{$this->host}";
$this->con = new PDO($dsn, $this->user, $this->password);

1142 Error using PDO in spite of using mysql_native_password

This question was marked earlier as a duplicate even though I had already implemented the most-searched solutions. I modified the MySql user to use native passwords using the following line (which did not fix my connection issue):
ALTER USER user_insert_ IDENTIFIED WITH mysql_native_password BY 'password123';
This code was a solution referenced here: phpMyAdmin on MySQL 8.0 (Also the solution from which this thread is marked as a duplicate)
1142 SELECT command denied to user
I am using MySQL 8.0 and php 7.3.0
I have granted full permissions for 'user_insert_'#'127.0.0.1', and am able to run the following SELECT statement fine from pymysql and MySQL Workbench, but not through PDO in php:
"SELECT * FROM worker_status"
The error I receive is:
Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1142 SELECT command denied to user 'user_insert_'#'localhost' for table 'worker_status' in C:\xampp\htdocs\hud\test_api_2\objects\activity.php:33
I expected to receive a single row response.
Here's the relevant code :
class Database{
private $host = "127.0.0.1";
private $db_name = "hud";
private $username = "user_insert_";
private $password = "password123";
private $charset = 'utf8mb4';
private $dsn = "";
public $conn;
public function getConnection(){
$this->conn = null;
$this->dsn = "mysql:host=$this->host;dbname=$this->db_name;charset=$this->charset";
print($this->dsn);
$this->options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$this->conn = new PDO($this->dsn, $this->username, $this->password, $this->options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
return $this->conn;
}
public function __construct($db){
$this->conn = $db;
}
function read(){
$query = "SELECT * FROM worker_status";
$stmt = $this->conn->prepare($query);
$stmt->execute();
$result = $stmt->fetch();
return $stmt;
}
Also, when trying to access phpmyadmin at "", I get a red error message referencing that caching_sha2_password is not enabled for broswer access.
I've checked:
show grants for 'user_insert_'#'127.0.0.1'; -- Which shows that all permissions are granted for that user.
There aren't any exceptions generated when the database connection starts.
The correct database and table is being connected to.
That my PDO syntax matches the documentation.
The user is already connecting using mysql_native_password ( Reference: phpMyAdmin on MySQL 8.0)
This seemed to me like a pretty vanilla case. Why am I getting a 1142 SELECT permission error exclusively with php PDO?

Too many connections with PDO persistent connection?

I've been struggling with this for quite a while, and it's to the point where I need to ask for help because even with all the research I've done I can't get a handle on why this is happening.
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [1040] Too many connections'
This happens upon loading a single page (index.php), and I am the only user (dev). As you can see here, the MySQL connection limit is set # 50 but I am narrowly surpassing that. This is an improvement over the 100~ connections that were being created before I refactored the code.
Here are the stats after the page has loaded once.
I've narrowed the issue down to several causes:
I don't fully understand how PDO/MySQL connections work.
I am creating too many connections in my code even though I am trying to only create one that I can share.
I need to increase the connection limit (seems unlikely).
Most of the SO questions I've found, tell the OP to increase the connection limit without truly knowing if that's the best solution so I'm trying to avoid that here if it's not needed. 50 connections for one page load seems like way too many.
These are the classes I am instantiating on the page in question.
$DataAccess = new \App\Utility\DataAccess();
$DataCopyController = new App\Controllers\DataCopyController($DataAccess);
$DriveController = new App\Controllers\DriveController($DataAccess);
$Helper = new App\Utility\Helper();
$View = new App\Views\View();
I am creating the DAL object then injecting it into the classes that need it. By doing it this way I was hoping to only create one object and one connection, however this is not what's happening obviously. Inside the DAL class I've also added $this->DbConnect->close() to each and every query method.
Here is the constructor for the DataAccess() class.
public function __construct() {
$this->DbConnect = new \App\Services\DbConnect();
$this->db = $this->DbConnect->connect("read");
$this->dbmod = $this->DbConnect->connect("write");
$this->Helper = new Helper();
}
Here is the DbConnect() class.
class DbConnect {
private $db;
private $dbmod;
private function isConnected($connection) {
return ($connection) ? TRUE : FALSE;
}
public function connect($access) {
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
];
if ($access == "read") {
if ($this->isConnected($this->db)) {
return $this->db;
} else {
if (strpos($_SERVER['SERVER_NAME'], DBNAME_DEV) === false) {
$this->db = new PDO("mysql:host=127.0.0.1; dbname=".DBNAME,
DBUSER,
DBPASS,
$options
);
} else {
$this->db = new PDO("mysql:host=" . DBHOST_DEV ."; dbname=".DBNAME_DEV,
DBUSER,
DBPASS,
$options
);
}
return $this->db;
}
} elseif ($access == "write") {
if ($this->isConnected($this->dbmod)) {
return $this->dbmod;
} else {
if (strpos($_SERVER['SERVER_NAME'], DBNAME_DEV) === false) {
$this->dbmod = new PDO("mysql:host=127.0.0.1; dbname=".DBNAME,
DBUSER_MOD,
DBPASS,
$options
);
} else {
$this->dbmod = new PDO("mysql:host=" . DBHOST_DEV . "; dbname=".DBNAME_DEV,
DBUSER_MOD,
DBPASS,
$options
);
}
}
return $this->dbmod;
}
}
public function close() {
$this->db = null;
$this->dbmod = null;
}
}
I've also tried instantiating the DbConnect() class on index.php and injecting that rather than DataAccess() but the result was the same.
EDIT:
I also want to add that this MySQL server has two databases, prod and dev. I suppose the connection limit is shared between both. However, the prod database gets very little traffic and I am not seeing this error there. When I refreshed the stats, there were no connections to the prod database.
From the PHP manual ~ http://php.net/manual/en/pdo.connections.php
Many web applications will benefit from making persistent connections to database servers. Persistent connections are not closed at the end of the script, but are cached and re-used when another script requests a connection using the same credentials.
So I would advise removing the DbConnection#close() method as you would not want to ever call this.
Also from the manual...
Note:
If you wish to use persistent connections, you must set PDO::ATTR_PERSISTENT in the array of driver options passed to the PDO constructor. If setting this attribute with PDO::setAttribute() after instantiation of the object, the driver will not use persistent connections.
So you'll want (at least)
new \PDO("mysql:host=127.0.0.1;dbname=" . DBNAME, DBUSER, DBPASS, [
PDO::ATTR_PERSISTENT => true
]);
You can also set your other connection attributes in the constructor.

Problems connecting to MySQL using PDO

I've been trying to convert my application from using the depreciated mysql syntax to PDO for connecting to the database and performing queries, and it's been a pain so far.
Right now I have a class, db_functions.php, in which I'm trying to create a PDO connection to the database, as well as perform all the CRUD operations inside of.
Here is a sampling of the code:
db_functions.php
<?php
class DB_Functions {
private $db;
// constructor
function __construct() {
require_once 'config.php';
// connecting to mysql
try {
$this->$db = new PDO('mysql:host=localhost;dbname=gcm', DB_USER, DB_PASSWORD);
}
catch (PDOException $e) {
$output = 'Unable to connect to database server.' .
$e->getMessage();
exit();
}
}
// destructor
function __destruct() {
}
public function getAllUsers() {
try {
$sql = "select * FROM gcm_users";
//$result = mysql_query("select * FROM gcm_users");
$result = $this->$db->query($sql);
return $result;
}
catch (PDOException $e) {
$error = 'Error getting all users: ' . $e->getMessage();
}
}
With that code, i'm getting the following error:
Notice: Undefined variable: db in C:\xampp\htdocs\gcm\db_functions.php on line 12
Fatal error: Cannot access empty property in C:\xampp\htdocs\gcm\db_functions.php on line 12
Line 12 is:
$this->$db = new PDO('mysql:host=localhost;dbname=gcm', DB_USER, DB_PASSWORD);
How could I fix this so that I have a proper instance of a PDO connection to my database that I can use to create queries in other methods in db_functions, such as getAllUsers()
I used the answer found at How do I create a connection class with dependency injection and interfaces? to no avail.
TYPO
//$this->$db =
$this->db =
same here
//$this->$db->query($sql);
$this->db->query($sql);
and i also would use 127.0.0.1 instead of localhost to improve the performance otherwise making a connection will take very long... a couple of seconds just for connection...

PHP designing OO database connection

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();
}
}
}

Categories