PDOExceptions and Bools

Hi i’m making a cms for my business and i need a little help trying to get my error exceptions outside of the class

here is an example of the database connection

‘’’

class siteDbh {
    private $host = '';
    private $user = '';
    private $pass = '';
    private $dbname = '';
    private $charset = '';

    protected function connect() {

        try {
            // Get the variable values used to connect and login
            $dsn = 'mysql:host='.$this->host.';dbname='.$this->dbname.';charset='.$this->charset;

            // Attempt to connect to the SQL database using PDO(Prepared Database Object)
            // Send the Database name, user and pass to the PDO class to try and connect
            $pdo = new PDO($dsn, $this->user, $this->pass);

            // Pre set attributes to use when making database querys
            $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

            return $pdo;

        } catch (PDOException $e) {

            die($e->getMessage());

        }
    }
}

‘’’

And then i have class’s for each part of my code with functions to SELECT, UPDATE, DELETE etc
So here is an example of one of them functions

‘’’

class siteHTTP extends siteDbh {

    // Select HTTP request
    public function request() {

        try {

            $sql = "SELECT http_request FROM settings WHERE 1";
            $stmt = $this->connect()->query($sql);

            return $stmt->fetch()['http_request'];

        } catch (PDOException $e) {

            return $e->getMessage();

        }

    }
}

‘’’

And then i would add these into my main file to be used

‘’’

// Prepared Database Object(PDO) SQL CONNECTION
//////////////////////////////////////////////////////////////////////
require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-dbh.class.php';
//#
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////



// Prepared Database Object(PDO) HTTP CLASS
////////////////////////////////////////////
require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-http.class.php';
$siteHTTP = new siteHTTP;
////////////////////////////////////////////

if (!$siteHTTP->request()) {
	$error[] = $siteHTTP->request();
	// Set default request
	$http_request = "https://";
} else {
	$http_request = $siteHTTP->request();
}

// Get URL Data - Force HTTPS or HTTP
// SITE HTTP Array
define('SITE_HTTP', array(
	'request' => $http_request
));
unset($http_request);

‘’’

My problem is “$siteHTTP->request()” is always TRUE. How can i return false and get my exception message when an Exception is caught??

I have an error array inside my main file and i would like to create an if else statement to see if the function is true or false while still getting the exception to put into my $error[].

Any help and advice is realy appreciated. Thank you.

You are already off to a less than optimal architecture.

First the good: You are using PDO and OOP

Starting with siteDbh

  1. The connection parameters should not be hard coded into the class. They should be passed in using Dependency Injection.

  2. Do not output internal system errors to the user. That info is only good to hackers. Log the error and display a generic error message to the user. You can also use set_exemption_handler to create a custom exception error handler which could also email you when there is an error as well as log it.

siteHTTP

  1. Do not extend the DB connection. Use Dependency Injection to pass it where it is needed.

  2. Do not litter your code base with try/catch blocks. Let Php handle the error or your custom exception handler. There are only a couple cases where you would use it, one being the DB connection as you already have, just don’t output the internal system errors.

  3. Do not output internal system errors to the user.

main file

  1. Not sure what all that http_request setting/ https stuff is about but it is funky and not something you should be doing. The site should ONLY use HTTPS and anything that has to do with redirecting requests to it should be done in the server conf file, virtual host conf file, or .htaccess
1 Like

OK no problem i will work on that… the http is part of my settings for header redirect, system links etc etc… is normaly like this

// Prepared Database Object(PDO) HTTP CLASS

////////////////////////////////////////////

require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-http.class.php';

$siteHTTP = new siteHTTP;

////////////////////////////////////////////

// Get URL Data - Force HTTPS or HTTP

// SITE HTTP Array

define('SITE_HTTP', array(

    'request' => $siteHTTP->request(),

    'domain' => $siteHTTP->domain(),

    'directory' => $siteHTTP->directory()

));

// Site URL - A combination of HTTP Request and Site Domain and Directory of site gives you a full URL string
define('SITE_URL', SITE_HTTP['request'].SITE_HTTP['domain'].SITE_HTTP['directory']);
//#

// Force HTTP HOST to be the actual HOST (yourdomain.com)
if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] != SITE_HTTP['domain']) {
	header('Location: '.SITE_HTTP['request'].SITE_HTTP['domain'].trim(htmlentities($_SERVER['REQUEST_URI'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')));
	exit;
} else if (isset($_SERVER['HTTP_HOST']) == false) {
	die('Access Denied!');
}
//#

// Force HTTPS - SSL TLS ON
if (SITE_HTTP['request'] === 'https://') {
	if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off") {
		//header('HTTP/1.1 301 Moved Permanently');
		header('Location: '.SITE_URL);
		exit;
	}
	// Force HTTP - SSL TLS OFF
} else if (SITE_HTTP['request'] === 'http://') {
	if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") {
		//header('HTTPS/1.1 301 Moved Permanently');
		header('Location: '.SITE_URL);
		exit;
	}
}
//#

also my functions normaly look like this…

class siteHTTP extends siteDbh {

    // Select HTTP request

    public function request() {

        $sql = "SELECT http_request FROM settings WHERE 1";

        if (!$stmt = $this->connect()->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['http_request'];

        }

    }

    //#

    // Select Domain

    public function domain() {

        $sql = "SELECT site_domain FROM settings WHERE 1";

        if (!$stmt = $this->connect()->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['site_domain'];

        }

    }

    //#

    // Select Directory

    public function directory() {

        $sql = "SELECT site_url_dir FROM settings WHERE 1";

        if (!$stmt = $this->connect()->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['site_url_dir'];

        }

    }

    //#

}

and then where i run a script in my mainfile and one of them functions returns false i exit and display a basic one time message like “sql error - user update” for example…

The email thing is a good idea for errors, i made a PostMan class i can use to do that

as for my DBH should i put my variables into a constructor? is that what you mean?

dbConfig.php
(To be more flexible for other DB types you can add another parameter for mysql:host. If using other DB types or team devs it would be a good idea to create a connection interface.)

<?php

return [
          'charset' =>'utf8mb4'
        , 'name' =>'exambuilder'
        , 'username' =>'root'
        , 'password' =>''
        , 'host' => 'localhost'
        , 'options'  =>[
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
            , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
            , PDO::ATTR_EMULATE_PREPARES => false
        ]
];

Connection.php

<?php

use PDO;

class Connection
{
    final public function connect(array $config): PDO
    {
        $dsn = "mysql:host={$config['host']};dbname={$config['name']};charset={$config['charset']}";
        return new PDO($dsn, $config['username'], $config['password'], $config['options']);
    }
}

Some common file…

<?php

$config = require 'dbConfig.php';
$pdo = (new Connection())->connect($config);

Your class

<?php
class YourClass
    {
        private $pdo;

        public function __construct(PDO $pdo)
        {
            $this->pdo = $pdo;
        }

        public function someMethod()
        {}

    }

Instantiate class

<?php

    $myClass= new YourClass($pdo);
1 Like

:sunglasses::nerd_face:

Is it safe/secure to have a return at root scope like that in a single file? I thaught this is what we have private class’s for?

thank you for your help

I use

if (!defined('some secret key')) {

    die('Access Denied!');

}

at the top of every file and use htaccess to secure directories but is that enough?

I used to use that type of thing. If you create/use a router you can move most of your files outside the public root directory which is much better for many reasons.

This is not the real file structure. Just shows the concept. The db connection would be instantiated in a bootstrap file outside the public web root.

1 Like

Great, i’ll work on it tomorrow and post back :nerd_face:

Hi i’m trying to implement what you have said and its not working out with my structure, its going to create too much code in the long run! If all your saying is dont have user pass etc all together with the connection handle then i can just split it all up into private and protected classes? resulting in no variables floating about my main file.

so i could just have…

class dbConfig
private/protected

class dbHandle extends dbConfig
private/protected

and then my someClass’s / some public functions can just extend my handle? This way i never have to create the extra variables or contrustors and the only thing getting called in my main file would me the functions as before… plus the config wont be visible to the public functions?? or anwhere else.

This is what i have come up with…

config file

class siteDbc {

    protected function cfg() {

        return [

            'host' => 'localhost'

            ,'username' => ''

            ,'password' => ''

            ,'name' => ''

            ,'charset' => 'utf8mb4'

            ,'options' =>[

                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION

                ,PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC

                ,PDO::ATTR_EMULATE_PREPARES => false

            ]

        ];        

    }

}

Handle file

class siteDbh extends siteDbc {

    protected function connect() {

        try {

            // Get the variable values used to connect and login
            $dsn = "mysql:host={$this->cfg()['host']};dbname={$this->cfg()['name']};charset={$this->cfg()['charset']}";

            // Attempt to connect to the SQL database using PDO(Prepared Database Object)
            // Send the Database name, user and pass to the PDO class to try and connect
            // Attribute "options" included
            return new PDO($dsn, $this->cfg()['username'], $this->cfg()['password'], $this->cfg()['options']);

        } catch (PDOException $e) {

            die($e->getMessage());

        }

    }

}

Then i include them in my main file

require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-dbc.cfg.php';
require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-dbh.class.php';

then a class of public functions for http settings to be used in the main file

class siteHTTP extends siteDbh {

    // Select HTTP request

    public function request() {

        $sql = "SELECT http_request FROM settings WHERE 1";

        if (!$stmt = $this->connect()->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['http_request'];

        }

    }

    //#

    // Select Domain

    public function domain() {

        $sql = "SELECT site_domain FROM settings WHERE 1";

        if (!$stmt = $this->connect()->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['site_domain'];

        }

    }

    //#

    // Select Directory

    public function directory() {

        $sql = "SELECT site_url_dir FROM settings WHERE 1";

        if (!$stmt = $this->connect()->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['site_url_dir'];

        }

    }

    //#

}

and then in my main file i do somthing like this

require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-http.class.php';

$siteHTTP = new siteHTTP;

// Get URL Data - Force HTTPS or HTTP

// SITE HTTP Array

define('SITE_HTTP', array(

    'request' => $siteHTTP->request(),

    'domain' => $siteHTTP->domain(),

    'directory' => $siteHTTP->directory()

));

And another example of using a function inside the main file and this checks for a genuine session

require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-checkUserSessionID.class.php';

    $verifyUserSessionID = new checkUserSessionID;

    ////////////////////////////////////////////

    // Check the users Session ID matches the Session ID in the database

    if (!$verifyUserSessionID->sidCheck($_SESSION['username'], $_SESSION['sessionid'])) {

        // This will only be called if a users active session ID

        // changes in the database due to logging into another device or an intruder

        // Session does not exist

        logout($sessionUpdateID, 'MIN');

        header('Location: '.SITE_URL.'?sysmsg=sidinvalid'.$sysMsgCon.$randSysMsgID);

        exit;

    }

It’s not going to work with your structure. The first thing I told you was your architecture was not good. Your last attempt is not right either.

I don’t understand… What won’t work?

For one, you need a router like I told you. Then you took separate files I posted and tried to stuff them together.

I suggest you go through this free Laracast video series.
The PHP Practitioner

1 Like

No worries i will get on that. Is it just my config and handle that i need to fix? the rest of my code is good enough?

Completley self taught here!!

It would take too long to try to explain what the videos already do. Just watch them when you can.

…OK. Thanks…

I finished the videos! Thank you!.. So i’ve done this…

Here is my config file

if (!defined('some secret key')) {

    die('Access Denied!');

}

return [

    'host' => 'localhost'

    ,'username' => ''

    ,'password' => ''

    ,'name' => ''

    ,'charset' => 'utf8mb4'

    ,'options' =>[

        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION

        ,PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC

        ,PDO::ATTR_EMULATE_PREPARES => false

    ]

];

My handle file or connection file…

namespace Site\Connection;

if (!defined('some secret key')) {

    die('Access Denied!');

}

// SITE DATABASE HANDLER

use Site\Connection\siteDbh, PDO;

class siteDbh {

    final public function connect(array $cfg): PDO {

        try {

    

            // Get the variable values used to connect and login

            $dsn = "mysql:host={$cfg['host']};dbname={$cfg['name']};charset={$cfg['charset']}";

    

            // Attempt to connect to the SQL database using PDO(Prepared Database Object)

            // Send the Database name, user and pass to the PDO class to try and connect

            // Attribute "options" included

            return new PDO($dsn, $cfg['username'], $cfg['password'], $cfg['options']);

    

        } catch (PDOException $e) {

    

            die('DB Connection Error!');

    

        }

    }

}

//#

Then in my main file…

////////////////////////////////////////////

// PDO CONNECTION

////////////////////////////////////////////

require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-dbh.class.php';

$sitePDO = (new Site\Connection\siteDbh())->connect(

    require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-dbh.cfg.php'

);

//#

And how i’m getting a pdo connectin to some methods (functions) …

class siteHTTP {

    private $pdo;

    public function __construct(PDO $pdo) {

        $this->pdo = $pdo;

    }

    // Select HTTP request

    public function request() {

        $sql = "SELECT http_request FROM settings WHERE 1";

        if (!$stmt = $this->pdo->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['http_request'];

        }

    }

    //#

    // Select Domain

    public function domain() {

        $sql = "SELECT site_domain FROM settings WHERE 1";

        if (!$stmt = $this->pdo->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['site_domain'];

        }

    }

    //#

    // Select Directory

    public function directory() {

        $sql = "SELECT site_url_dir FROM settings WHERE 1";

        if (!$stmt = $this->pdo->query($sql)) {

            return false;

        } else {

            return $stmt->fetch()['site_url_dir'];

        }

    }

    //#

}

Finaly how i call the class to use in my main file and small example of being used…

// Prepared Database Object(PDO) HTTP CLASS

////////////////////////////////////////////

require_once INCLUDES_BASEDIR.'_site_pdo/_sitePDO-http.class.php';

$siteHTTP = new siteHTTP($sitePDO);

////////////////////////////////////////////

// Get URL Data - Force HTTPS or HTTP

// SITE HTTP Array

define('SITE_HTTP', array(

    'request' => $siteHTTP->request(),

    'domain' => $siteHTTP->domain(),

    'directory' => $siteHTTP->directory()

));

// Site URL - A combination of HTTP Request and Site Domain and Directory of site gives you a full URL string

define('SITE_URL', SITE_HTTP['request'].SITE_HTTP['domain'].SITE_HTTP['directory']);

//#

I understand now why to use namespace and come to like the idea. I will be working on learning the routing but my method is still ok for now. Is my progress Valid? Thank you very much for help!

Sponsor our Newsletter | Privacy Policy | Terms of Service