More detailed exceptions - php

I've nearly finished converting my old sql website to pdo to move to php7 and use prepared statements but im having trouble with a handful of errors.
The exceptions are not as clear as i would like, most errors point to my database class eg
Uncaught Exception: 2020-01-18 20:23:35 - SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'username' AND UNIX_TIMESTAMP('2020-01-18 20:23:35')-UNIX_TIMESTAMP(date) < 30' at line 1 in file /home/test/public_html/backend/dbclass.php on line 39
Uncaught Exception: 2020-01-18 20:23:43 - SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '86.28.135.16'', donated=0, forumbanned='no', warned='no', modcomment='', enabled' at line 1 in file /home/test/public_html/backend/dbclass.php on line 39
I am using a blunt singleton class this was the easiest way (i known this is not the best) and i had 1000 queries so a global static suited me to make it quicker. I would prefer not to wrap every query in try/catch to identify exceptions. Is they any function that might help like backtrace or gettrace im a novice so maybe theres a better way any help would be very appreciated
dbclass.php
<?php
define('DB_HOST', 'host');
define('DB_NAME', 'db');
define('DB_USER', 'user');
define('DB_PASS', 'pass');
define('DB_CHAR', 'utf8');
class DB
{
protected static $instance = null;
protected function __construct() {}
protected function __clone() {}
public static function instance()
{
if (self::$instance === null)
{
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => FALSE,
);
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHAR;
self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opt);
}
return self::$instance;
}
public static function __callStatic($method, $args)
{
return call_user_func_array(array(self::instance(), $method), $args);
}
public static function run($sql, $args = [])
{
if (!$args)
{
return self::instance()->query($sql);
}
$stmt = self::instance()->prepare($sql);
$stmt->execute($args);
return $stmt;
}
}
exception_handler
function handleUncaughtException($e){
// Show general page to public
header("Location: exceptionerror.php");
// Construct the error string
$error = "Uncaught Exception: " . $message = date("Y-m-d H:i:s - ");
$error .= $e->getMessage() . " in file " . $e->getFile() . " on line " . $e->getLine() . "\n";
// Log details of error in a file
error_log($error, 3, "error_log.txt");
}
// Register custom exception handler
set_exception_handler("handleUncaughtException");
example of query
$stmt = DB::run("SELECT word FROM censor ORDER BY word");
while ($row = $stmt->fetch())

Related

PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function Kit\core::__construct() on PDO class

I am currently looking at improving my PHP knowledge and creating websites to a better extent by using classes and such but I've ran into an issue when trying to allow other classes in separate files to access the PDO connection that I've sent up. I've tried hundreds of resolutions which have been inputted onto this site but can't seem to figure it out at all and can't seem to understand where I'm going wrong.
I'm being met with the following error:
[16-Sep-2022 11:05:02 UTC] PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function Kit\core::__construct(), 0 passed in /home/liamapri/public_html/kit/global.php on line 24 and exactly 1 expected in /home/liamapri/public_html/kit/app/class.core.php:11
Stack trace:
#0 /home/liamapri/public_html/kit/global.php(24): Kit\core->__construct()
#1 /home/liamapri/public_html/index.php(3): include_once('/home/liamapri/...')
#2 {main}
thrown in /home/liamapri/public_html/kit/app/class.core.php on line 11
I have a global.php file which will be added to each individually page such as /home /index etc, it references all the files that I'll need and starts the session from it, see below:
error_reporting(E_ALL ^ E_NOTICE);
define('C', $_SERVER["DOCUMENT_ROOT"].'/kit/conf/');
define('A', $_SERVER["DOCUMENT_ROOT"].'/kit/app/');
define('I', 'interfaces/');
// Management
require_once C . 'config.php';
// Interfaces
require_once A . I . 'interface.engine.php';
require_once A . I . 'interface.core.php';
require_once A . I . 'interface.template.php';
// Classes
require_once A . 'class.engine.php';
require_once A . 'class.core.php';
require_once A . 'class.template.php';
// OBJ
$engine = new Kit\engine();
$core = new Kit\core();
$template = new Kit\template();
// Start
session_start();
$template->Initiate();
This references the class.engine.php first which is where I have created the database connection class, as shown below:
namespace Kit;
use PDO;
if(!defined('IN_INDEX')) { die('Sorry, this file cannot be viewed.'); }
class engine
{
public $pdo;
public function __construct()
{
global $_CONFIG;
$dsn = "mysql:host=".$_CONFIG['mysql']['hostname'].";dbname=".$_CONFIG['mysql']['database'].";charset=".$_CONFIG['mysql']['charset'].";port=".$_CONFIG['mysql']['port'].";";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$this->pdo = new PDO($dsn, $_CONFIG['mysql']['username'], $_CONFIG['mysql']['password'], $options);
} catch (\PDOException $e) {
print "<b>An error has occurred whilst connecting to the database:</b><br />" . $e->getMessage() . "";
die();
}
}
}
$connection = new engine();
I'm then trying to run a PDO query on another class (class.core.php) and keep getting met with either a PDO can't be found error or the one described above.
See the file below:
namespace Kit;
if(!defined('IN_INDEX')) { die('Sorry, this file cannot be viewed.'); }
class core implements iCore
{
public $connection;
public function __construct($connection)
{
$this->connection = $connection;
}
public function website_settings()
{
$qry = $this->connection->pdo->prepare("SELECT `website_name` FROM `kit_system_settings`");
$qry->execute([]);
if ($qry->rowCount() == 1) { while($row = $qry->fetch()) { return $row; } }
}
}
Sorry if this is a simple fix but I really can't see where I'm going wrong.
Look in your global .php on Line 24 (its probably this line: $core = new Kit\core();)
In your class.core.php you tell the constructor that it will get a connection, but in your global.php you dont give constructor (when you initialize a class) any argument.
That's what this error is telling you
PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function Kit\core::__construct(), 0 passed
Just guessing, but i think
$core = new Kit\core($engine->pdo);
will fix your issue.

How to make a reusable SELECT method in OOP php [duplicate]

This question already has answers here:
How can I fix MySQL error #1064?
(3 answers)
How can I prevent SQL injection in PHP?
(27 answers)
Closed 2 years ago.
im new here and im also pretty new to php and OOP so if i dont ask the right question also tell me ;p
im trying to make a class that handles all the queries from and to the database. I want to make this class as reusable as plossible so i dont have to keep writing selects and insert statements in all my methods and functions.
my question is: is it plossible to call on an method with parameters and then have those parameters finish the query for me ?
this is what i had come up with so far:
Database connection class:
class Database {
private $host;
private $user;
private $pass;
private $dbname;
private $charset;
public function connect() {
$this->host = 'localhost:3306';
$this->user = 'root';
$this->pass = '';
$this->dbname = 'Testdb';
$this->charset = 'utf8mb4';
try {
$dsn = 'mysql:host='.$this->host.';dbname='.$this->dbname.';charset='.$this->charset;
$pdo = new PDO($dsn, $this->user, $this->pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
} catch (PDOException $e) {
echo "Connection failed:".$e->getMessage();
}
}
}
this is my query's class:
class QueryDatabase extends Database {
public function getData($tablename, $selector, $value) {
if (!isset($selector)){
echo 'Something went wrong!';
} else if ($selector == ''){
$stmt = $this->connect()->query("SELECT * FROM $tablename");
while ($row = $stmt->fetch()){
return $row;
}
}else {
$stmt = $this->connect()->query("SELECT * FROM $tablename where $selector = $value");
while ($row = $stmt->fetch()){
return $row;
}
}
}
public function setData($tablename, $colums, $data) {
if (!isset($tablename) or !isset($data)) {
echo 'Something went wrong!';
} else {
$sql = "INSERT INTO $tablename ($colums) VALUES ($data)";
$q = $this->connect()->prepare($sql);
$q->execute();
}
}
protected function addData() {
}
protected function delData() {
}
}
and this is what i mean with the parameters for example:
$test = new QueryDatabase;
$test->setData('contact_form_messages', 'u_id, name, email, subject, message, date', ' , Kees, Kees#gmail.com, Test, Hopefully it works, ');
i get this error message :
Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ' Kees, Kees#gmail.com, Test, Hopelijk werkt hij, )' at line 1 in D:\webProjects\project\classes\querydatabase.class.php:31
Stack trace: #0 D:\webProjects\project\classes\querydatabase.class.php(31): PDOStatement->execute() #1 D:\webProjects\project\includes\header.inc.php(5):
QueryDatabase->setData('contact_form_me...', 'u_id, name, ema...', ' , Kees, Kees#g...') #2 D:\webProjects\project\contact.php(1): include('D:\\webProjects\\...') #3 {main} thrown in D:\webProjects\project\classes\querydatabase.class.php on line 31
if you have any suggestions i'd be happy to hear them!
thanks a lot!
Floris

Uncaught PDOException for SQLite - unable to open database file

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

mysqli query returns false but no error message

I have a very straightforward SELECT query within the context of a PHP class which is returning false (failed) but I am unable to retrieve the associated error information. The odd thing is that the call worked fine until I had to reorganize the mysql database - without revising the PHP code obviously it fails - the result is false - but where is the error message?
Code is as follows:
<?php
class Database {
private $_connection;
private $_result;
private $_lastQuery;
private $_error;
public function __construct($dbase) {
$this->_connection = new mysqli(DB_SERVER, DB_USER, DB_PASS, $dbase);
if (mysqli_connect_error()) {
trigger_error("failed to connect to MySQL: " . mysqli_connect_error(), E_USER_ERROR);
}
mysqli_set_charset($this->_connection, 'utf8');
}
public function query($query) {
$this->_lastQuery = $query;
$this->_result = mysqli_query($this->_connection, $query);
$this->_error = $this->_connection->error;
return $this->_result;
}
}
No error string appears in $this->_error; also not revealed when inspected during debugging (PHPStorm).
When executing the query via the command line, the (expected) error messaging is generated.
It appears that the problem is actually with xdebug.

PDO: MySQL server has gone away

I have a script that does a lot of legwork nightly.
It uses a PDO prepared statement that executes in a loop.
The first few are running fine, but then I get to a point where they all fail with the error:
"MySQL server has gone away".
We run MySQL 5.0.77.
PHP Version 5.2.12
The rest of the site runs fine.
Most likely you sent a packet to the server that is longer than the maximum allowed packet.
When you try to insert a BLOB that exceeds your server's maximum packet size, even on a local server you will see the following error message on clientside:
MySQL server has gone away
And the following error message in the server log: (if error logging is enabled)
Error 1153 Got a packet bigger than 'max_allowed_packet' bytes
To fix this, you need to decide what is the size of the largest BLOB that you will ever insert, and set max_allowed_packet in my.ini accordingly, for example:
[mysqld]
...
max_allowed_packet = 200M
...
The B.5.2.9. MySQL server has gone away section of the MySQL manual has a list of possible causes for this error.
Maybe you are in one of those situations ? -- Especially considering you are running a long operation, the point about wait_timeout might be interesting...
I had the same problem where the hosting server administration kills connection if there is a timeout.
Since I have used the query in major part I wrote a code which instead of using PDO class we can include the below class and replace the classname to "ConnectionManagerPDO". I just wrapped the PDO class.
final class ConnectionManagerPDO
{
private $dsn;
private $username;
private $passwd;
private $options;
private $db;
private $shouldReconnect;
const RETRY_ATTEMPTS = 3;
public function __construct($dsn, $username, $passwd, $options = array())
{
$this->dsn = $dsn;
$this->username = $username;
$this->passwd = $passwd;
$this->options = $options;
$this->shouldReconnect = true;
try {
$this->connect();
} catch (PDOException $e) {
throw $e;
}
}
/**
* #param $method
* #param $args
* #return mixed
* #throws Exception
* #throws PDOException
*/
public function __call($method, $args)
{
$has_gone_away = false;
$retry_attempt = 0;
try_again:
try {
if (is_callable(array($this->db, $method))) {
return call_user_func_array(array($this->db, $method), $args);
} else {
trigger_error("Call to undefined method '{$method}'");
/*
* or
*
* throw new Exception("Call to undefined method.");
*
*/
}
} catch (\PDOException $e) {
$exception_message = $e->getMessage();
if (
($this->shouldReconnect)
&& strpos($exception_message, 'server has gone away') !== false
&& $retry_attempt <= self::RETRY_ATTEMPTS
) {
$has_gone_away = true;
} else {
/*
* What are you going to do with it... Throw it back.. FIRE IN THE HOLE
*/
throw $e;
}
}
if ($has_gone_away) {
$retry_attempt++;
$this->reconnect();
goto try_again;
}
}
/**
* Connects to DB
*/
private function connect()
{
$this->db = new PDO($this->dsn, $this->username, $this->passwd, $this->options);
/*
* I am manually setting to catch error as exception so that the connection lost can be handled.
*/
$this->db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
/**
* Reconnects to DB
*/
private function reconnect()
{
$this->db = null;
$this->connect();
}
}
Then use can start using the above class as you do in PDO.
try {
$db = new ConnectionManagerPDO("mysql:host=localhost;dbname=dummy_test", "root", "");
$query = $db->query("select * from test");
$query->setFetchMode(PDO::FETCH_ASSOC);
}
catch(PDOException $e){
/*
handle the exception throw in ConnectionManagerPDO
*/
}
Try using PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, true) on your pod instance(s). Dont know that it will help but with no log data its all i got.
It's likely that either your connection has been killed (e.g. by wait_timeout or another thread issuing a KILL command), the server has crashed or you've violated the mysql protocol in some way.
The latter is likely to be a bug in PDO, which is extremely likely if you're using server-side prepared statements or multi-results (hint: Don't)
A server crash will need to be investigated; look at the server logs.
If you still don't know what's going on, use a network packet dumper (e.g. tcpdump) to dump out the contents of the connection.
You can also enable the general query log - but do it very carefully in production.
Nathan H, below is php class for pdo reconnection + code usage sample.
Screenshot is attached.
<?php
# set errors reporting level
error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
# set pdo connection
include('db.connection.pdo.php');
/* # this is "db.connection.pdo.php" content
define('DB_HOST', 'localhost');
define('DB_NAME', '');
define('DB_USER', '');
define('DB_PWD', '');
define('DB_PREFIX', '');
define('DB_SHOW_ERRORS', 1);
# connect to db
try {
$dbh = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PWD);
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
# echo $e->getMessage()."<br />";
# exit;
exit("Site is temporary unavailable."); #
}
*/
$reconnection = new PDOReconnection($dbh);
$reconnection->getTimeout();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;
echo 'sleep 10 seconds..'.PHP_EOL;
sleep(10);
$dbh = $reconnection->checkConnection();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;
echo 'sleep 35 seconds..'.PHP_EOL;
sleep(35);
$dbh = $reconnection->checkConnection();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;
echo 'sleep 55 seconds..'.PHP_EOL;
sleep(55);
$dbh = $reconnection->checkConnection();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;
echo 'sleep 300 seconds..'.PHP_EOL;
sleep(300);
$dbh = $reconnection->checkConnection();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;
# *************************************************************************************************
# Class for PDO reconnection
class PDOReconnection
{
private $dbh;
# constructor
public function __construct($dbh)
{
$this->dbh = $dbh;
}
# *************************************************************************************************
# get mysql variable "wait_timeout" value
public function getTimeout()
{
$timeout = $this->dbh->query('show variables like "wait_timeout"')->fetch(); # print_r($timeout);
echo '========================'.PHP_EOL.'mysql variable "wait_timeout": '.$timeout['Value'].' seconds.'.PHP_EOL.'========================'.PHP_EOL;
}
# *************************************************************************************************
# check mysql connection
public function checkConnection()
{
try {
$this->dbh->query('select 1')->fetchColumn();
echo 'old connection works..'.PHP_EOL.'========================'.PHP_EOL;
} catch (PDOException $Exception) {
# echo 'there is no connection.'.PHP_EOL;
$this->dbh = $this->reconnect();
echo 'connection was lost, reconnect..'.PHP_EOL.'========================'.PHP_EOL;
}
return $this->dbh;
}
# *************************************************************************************************
# reconnect to mysql
public function reconnect()
{
$dbh = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PWD);
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}
}
# /Class for PDO reconnection
# *************************************************************************************************
I got this same error this morning after changing my DB properties in Laravel. I'd commented out the old settings and pasted in new ones. The problem was that the new settings where missing the DB_CONNECTION variable:
DB_CONNECTION=pgsql
Obviously you need to add whatever connection type you are using: sqlite, mysql, ...
I had the exact same problem.
I resolved this issue by doing unset on the PDO object instead of seting it to NULL.
For example:
function connectdb($dsn,$username,$password,$driver_options) {
try {
$dbh = new PDO($dsn,$username,$password,$driver_options);
return $dbh;
}
catch(PDOException $e)
{
print "DB Error: ".$e->getMessage()."<br />";
die();
}
}
function closedb(&$dbh) {
unset($dbh); // use this line instead of $dbh = NULL;
}
Also, it is highly recommended to unset all your PDO objects. That includes variables that contain prepared statements.
$pdo = new PDO(
$dsn,
$config['username'],
$config['password'],
array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)
);
try this. It may work

Categories