PDOExceptions and Bools

: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!

Your getting there. Just keep learning.

In your current class siteHTTP the else is not needed. Just do like so…

if (!$stmt = $this->pdo->query($sql)) {
    return false;
}

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

NO. You are writing out a method for each piece of data. If you add a new data value, you should NOT need to touch the code. If you had 30 different settings, do you think writing out 30 different methods would be a good idea? You should have either a (one) general-purpose get method, that accepts the setting name as an input parameter or you should use a magic __get() method. You should also not have a column for each setting. You should instead have a separate row for each setting.

Since you are using exceptions for database statement errors, if the ->query() method call in that code fails, execution transfers to the nearest PDO exception handler, or to php if there is no specific PDO exception handler. There’s no point in the if() conditional logic or the return false statement since that code is not executed upon an error.

One of the points about using exceptions is that your ‘main’ code only has to deal with error free execution, since execution transfers elsewhere upon an error, simplifying your code. There’s no need for any conditional logic testing returned values and the only time you should have a try/catch block is when its possible to ‘recover’ from an error, such as when inserting/updating duplicate or out of range user data.

OK I will work on that…

Some times i do need a return of true or false and here is an example…
In its own class to seperate. I dont want to load all my classes at once i only load them where i need them. Would i use an array of Name values to put into it then(regarding above post about my settings)? Where would i keep that array? inside that class at the top ? or in the Function?
I check if the users session id is genuine if not return false…

class checkUserSessionID {

    private $pdo;

    public function __construct(PDO $pdo) {

        $this->pdo = $pdo;

    }

    // Site account sessions

    public function sidCheck($username, $sid) {

        //check that the username and password match and return true or false

        $stmt = $this->pdo->prepare('SELECT sessionid FROM users WHERE username = ?');

        if ($stmt->execute([$username]) && password_verify($sid, $stmt->fetch()['sessionid'])) {

            return true;

        } else {

            return false;

        }

    }

}

and in my main file

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

    $verifyUserSessionID = new checkUserSessionID($sitePDO);

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

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

    }

If i don’t have the if statement how would i know the users session id didon’t match?? That applies to the function above.

Generaly i need to know if my PDO $stmt was true or false…

7 Answers. Method is actually a function used in the context of a class/object. When you create a function outside of a class/object, you can call it a function but when you create a function inside a class, you can call it a method . So an object can have methods ( functions ) and properties (variables). That’s from stack overflow on a google search… And is how i referenced it above.

The 2nd and 3rd paragraphs I wrote in that reply have to do with using exceptions for database statement errors, and they were with respect to the previous code you posted. They don’t have anything to do with your application logic.

No, you don’t. Do you even know what would cause $stmt to be a false value or what would cause $stmt->execute([$username]) to be a false value?

I suspect you think that a query that matches no data produces an error. It does not. It is a successful query that just has no rows in the result set.

Some of the things that would cause $stmt or$stmt->execute([$username]) to be a false value -

  1. No database selected.
  2. An sql syntax error.
  3. Wrong table/column names.
  4. Inserting/updating duplicate values, out of range values, or null values where nulls are not allowed.

Items 1-3 are programming mistakes. Item 4 has to do with wrong data values, some of which are programming mistakes and in the case of a duplicate value is something that your code should detect and attempt to recover from.

In the last code you posted, including $stmt->execute([$username]) in the conditional test is pointless. When using exceptions for errors, if the ->execute() call produced an error, program execution goes to the nearest PDO exception handler, and all the rest of the code in that method is not executed. Your conditional test should only be concerned with the value from password_verify().

1 Like
Sponsor our Newsletter | Privacy Policy | Terms of Service