I'm trying to make the transition to OOP PHP to help clean up the cluster of code I'm currently working with.
I'm using PHPass to hash passwords in my database but with this OOP approach, I can't get my head around how to call it in my class' login function.
As far as I can see, in all the places I've tried calling it, it's always declared before my class is initialised but it's still telling my it's undefined or a non-object.
db_config.php
...
require_once("PasswordHash.php"); // Location no.1 to try it
$password_hash = new PasswordHash(8, FALSE);
include_once("DB.php");
$db = new DB($db_connection);
...
init.php
//require_once("PasswordHash.php"); // Location no.2 to try it
//$password_hash = new PasswordHash(8, FALSE);
require_once("db_config.php")
..Other init stuff..
DB.php
class DB {
...
public function login() {
// global $password_hash; -> if uncommented I get an error saying it's a non-object
// Error here
$password_accepted = $password_hash->CheckPassword($p, $hp);
}
...
}
login.php
require_once("init.php");
$db->login();
I still haven't got my head fully around how class scope works in PHP so I have a feeling I'm missing something.
You need to pass the hash into the class as the class has only an internal scope.
$formData = array();
$formData['email'] = 'user#email.com';
require_once("PasswordHash.php"); // Location no.1 to try it
$formData['password_hash'] = new PasswordHash(8, FALSE);
include_once("DB.php");
$db = new DB($db_connection, $formData);
and in DB.php:
class DB {
// Stores the user input form data for use within the class?
private $formData;
// Runs when the class is constructed
public function __construct($formData)
{
// When the class is constructed then store this for local/interal use
$this->$formData = $formData;
}
public function login() {
// The boolean result of of checking of an internal method
// that compares user credentials against the database information?
$password_accepted = $this->CheckPassword(
$this->formData['email'],
$this->formData['password_hash']
);
}
private function CheckPassword($email, $pass) {
// Do query and bind in $user and $pass
// Return true if everthing passes
}
}
Edit: I exaggerated the use of passing the variables into classes and methods to help you to wrap your head around this aspect of things but you could also do something like:
...
$password_accepted = $this->CheckPassword();
}
private function CheckPassword() {
// Do query and bind in $this->formData['email'] and $this->formData['password_hash']
// Return true if everthing passes
}
}
Just inject the hash instance the same way you already do with the db_connection.
class DB {
...
public function __construct($db_connection, $password_hash) {
// you probably already have something like
$this->connection = $db_connection;
// now do the same for the hash object
$this->pwhash = $password_hash;
}
public function login() {
...
$password_accepted = $this->pwhash->CheckPassword($p, $hp);
...
}
}
(slightly offtopic: Database and Hash ...along with Cipher, EMail and Buffer these are my least liked classes for beginners to fiddle with)
Related
I'm a little new to OO programming and am having trouble grasping why one mechanism works and another does not.
I've create a simple class that is to return a MySQL database handle. My attempt at returning the handle directly from a constructor fails. But succeeds from either a class method or from a class(?) method after an instance has been created. Here's the class definition and the sample script
<?php
class HMMDatabaseHandle {
private static $configfile = "config.json";
// uncomment for test 1
// public function __construct () {
// return self::get_handle_admin();
// }
public static function create() {
return self::get_handle_admin();
}
private static function get_handle_admin() {
$config = json_decode(file_get_contents(self::$configfile));
$dbhost = $config->database->dbhost;
$dbname = $config->database->dbname;
$dbuser = $config->database->dbuser;
$dbpass = $config->database->dbpass;
try {
return new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
}
catch(PDOException $e) {
echo $e->getMessage();
}
}
}
?>
And here is the test script I'm using:
<?php
require_once 'HMMDatabaseHandle.php';
// Test 1 - fails (uncomment constructor func) at call to prepare() with:
// PHP Fatal error: Call to undefined method HMMDatabaseHandle::prepare()
//$dbh = new HMMDatabaseHandle();
// Test 2 - works when class creates default constructor
// i.e. no explicit __construct() func
// Fetching data from executed query is fine
//$db = new HMMDatabaseHandle();
//$dbh = $db->create();
// Works using static class methods rather than instance
$dbh = HMMDatabaseHandle::create();
$sth = $dbh->prepare('select data_title,track_id from master');
$sth->execute();
while($row = $sth->fetch(PDO::FETCH_ASSOC)) {
...
}
My questions are:
Why can't I return the handle directly from a constructor when it seems so similar to calling the class method directly? Why does it matter whether the constructor calls the class method or my script calls it?
If I create an instance with PHP's default constructor, am I really calling a class method with $db->create()?
I seem to be missing some fundamental concept here. Thanks in advance!
You can't return the handle from the constructor in that context because that would violate the defined behavior of new. new SomeClass(); will only ever return an instance of the class, regardless of what other methods are called in the constructor.
__construct() is a void method. It is not intended to return anything1. That doesn't mean that the other code in it doesn't get executed, just that your return is disregarded in the context of creating a new object. This makes sense as the primary purpose for the constructor is to provide a means to pass dependencies to the object. Sometimes it is used to do additional initialization/setup of the object, but many people believe it should not do any work other than assigning the given arguments to the object's properties. Either way, there should be no need for it to return anything.
1 You can actually call the __construct() method explicitly after you create the object, and then it will behave like a normal method and your return will work.
$db = new HMMDatabaseHandle();
$dbh = $db->__construct();
var_dump($dbh); // PDO Object
This isn't a normal thing to do though, and I can't think of a scenario where it would be useful or desirable. I just wanted to point out that it is possible.
Why can't I return the handle directly from a constructor when it
seems so similar to calling the class method directly?
If you were able to do that, then you wouldn't have an instance of HMMDatabaseHandle; you'd have an instance of PDO. How would you access any other methods that HMMDatabaseHandle provides?
While I fully agree with #Don't Panic's answer, I need to also point out that you're mixing static and instance methods.
As a general rule of thumb, use the static keyword when you want to be able to call a method without instantiating the object first. If you want to actually create and use an object, then you can define you class like so and use $this-> (or $object-> if outside of the class) instead of :: to access instance properties and methods.
<?php
class HMMDatabaseHandle
{
private $configfile = "config.json";
public function __construct()
{
// You're not initializing anything in here, so this constructor is optional.
}
public function create()
{
return $this->get_handle_admin();
}
private function get_handle_admin()
{
$config = json_decode(file_get_contents($this->configfile));
$dbhost = $config->database->dbhost;
$dbname = $config->database->dbname;
$dbuser = $config->database->dbuser;
$dbpass = $config->database->dbpass;
try {
return new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
}
catch (PDOException $e) {
echo $e->getMessage();
}
}
}
To actually execute this, you need to now instantiate new class.
$dbManager = new HMMDatabaseHandle();
$handle = $dbManager->create();
Finally, there is a trick you can employ to make your constructor chainable. Simply wrap it in brackets.
$handle = (new HMMDatabaseHandle())->create();
Alright I have a few classes and I'm wanting to pass on an initiated class object but I keep getting errors. It'll work one time, then other times I'll get a
PHP Fatal error: Cannot redeclare class
I don't know what I'm doing wrong. I'm basically trying to clean up my code because I'm ALWAYS having 2-3 includes for every one of my pages. I'd rather just include one class and pass on or use the other classes instances from there. Here's an example of what I have now:
Manage.php - Main Class
<?php
include_once('/path/to/DB.php');
class Manage {
public $db;
public function __construct() {
$this->db = new DB($host,$dbName,$user,$pass);
//other constructor stuff
}
//other functions
}
DB.php - Helper Class
<?php
class DB {
public $conn;
public function __construct($host = false, $db = false, $user = false, $pass = false) {
//connect to database
}
//functions for interacting with the database (get,query,update,insert, etc)
}
UseOfClass.php - Shows how I'd like to use it
<?php
include('/path/to/Manage.php');
$manage = new Manage();
$results = $manage->db->get('table_name');
print_r($results);
I have a PHP class with a few functions defined, this class is responsible for database access:
class database {
function open($params) {
// code here to open the db
}
function close() {
// code here to close the db
}
function count_users() {
// code here counts the number of user records
// Return -1 for testing
return -1;
}
function insert_user($user) {
// code here inserts a user record
}
function select_user($user_id) {
// code here selects a user record
}
}
I have accessor classes defined as follows:
require_once("database.php");
class user {
public $user_id;
public $email_address;
// etc, etc
}
class db_user {
static function select_user($user_id) {
$db = new database();
$db->open();
$user = NULL;
$result = $db->select_user($user_id);
// Test the result and decode user record into $user, etc
$db->close();
return $user;
}
static function count_users() {
$db = new database();
$db->open();
$count = $db->count_users();
$db->close();
return $count;
}
}
My issue occurs when I attempt to count the number of users through db_user::count_users(); which always fails with a Fatal Error: call to undefined method database::count_users
If I dump the database class methods using get_class_methods, I can see that the count_users function isn't present in the list but I have no idea why.
I'm very much a PHP n00b so there maybe something really obvious I'm not doing. My db_user and user classes have many other functions which pull data back through the database class and all of these succeed - just this one function.
Please help!
UPDATE
Ok, so, having removed a couple of functions from the database class and re-uploaded the file to the live server, it appears that it is somehow being "cached" as when I dump the methods belonging to the database object, the removed methods are still displayed in the list.
The count_users function is also not present in the method list yet when I inspect the file uploaded to the server, it is there in code.
Is there any way of removing this caching???
Try as follows:
class user extends database {
//code user class goes here
}
or
class user extends db_user {
//code user class goes here
}
simple problem solved.
You can store you instance of Database to the variable.
class db_user {
public static $db;
static function openDatabase(){
self::$db = new database();
self::$db->open();
}
static function select_user($user_id) {
$user = NULL;
$result = self::$db->select_user($user_id);
// Test the result and decode user record into $user, etc
self::$db->close();
return $user;
}
static function count_users() {
$count = $db->count_users();
self::$db->close();
return $count;
}
}
The issue, it would appear, is related to another version of the "database.php" file hiding in a sub-folder which must have been copied there by mistake.
Having removed this troublesome file, all now works as expected.
Thanks for your help.
Tried running your code in on-line phptester tool - first complained about missing $params in $db->open(), removing the argument (or passing the $params) it works fine on php 5.2,5.3,5.4. No complaints about count_users().
Hi I want to add some functionality to the session_start function in php. I know I can write a custom function to replace session_start() but that goes too far. I just want to have some additional code trigger, not remove the old code.
Edit: Specifically I want the session ID to be written into a sql table.
You could simply create a function wrapper around session_start() that you use.
function my_session_start() {
session_start();
$session_id = session_id();
// write $session_id to database by whatever method you choose
}
// usage
my_session_start();
Or if you want to extend on sessionHandler you could do something like this:
class mySessionHandler extends sessionHandler {
// perhaps a property to store db connection or DB object as needed for writing session id to database
protected $db = null;
public function __construct($db = null) {
if(is_null($db)) {
throw new Exception('Give me a database');
}
// maybe some other validation (could also use type hinting in parameter
$this->db = $db;
}
public function open($save_path, $session_id) {
parent::open($save_path, $session_id);
// not shown - use $this->db to insert $session_id to database
}
}
// usage
$session_handler = new mySessionHandler($db);
session_set_save_handler($session_handler, true);
session_start();
Here you are only overriding the open() method to add the session id to the database.
I am fairly new to object oriented programming. I made this class which connects to mysql database to be called from models. Is there any way i can include 'database.class.php'(my db class file)
in index.php, make it global and then access it from any object like so
$object = new object;
$object->dofunc();
Also another question is dofunc() expects an array for argument, how do i make this array also global so it can be accessed from ANY where!
Here is my db class
<?php
class Database {
private $db;
public function connect($config) {
if (is_array($config)) {
extract($config);
$db = mysqli_connect($host, $username, $password);
if ($db) {
echo "balbabla";
if (mysqli_select_db($db, $database)) {
}
else {
throw new exception("<br/><strong>Could not connect to $database under $host</strong>");
}
}
else {
throw new exception("<br/><strong>Could not connect to mySQL database! Please check your details</stromg>");
}
}
}
}
?>
Also this is the file that contains the array
<?php
//Configuration for the MVC Framework
$_SETTINGS = array();
//Routing settings!
//Default controller(This controller will be loaded if there is none mentioned in the URI)
$_SETTINGS['default_controller'] = 'User';
//Default method(This will be the default method run if no method is mentioned in the URI)
$_SETTINGS['default_method'] = 'Register';
//Database settings
$DB_SETTINGS['host'] = 'localhost';
$DB_SETTINGS['username'] = 'root';
$DB_SETTINGS['password'] = 'foobar';
$DB_SETTINGS['database'] = 'freelance';
?>
Thanks in advance
Is there any way i can include 'database.class.php'(my db class file) in index.php, make it global
You can, but you shouldn't.
Also another question is dofunc() expects an array for argument, how do i make this array also global so it can be accessed from ANY where!
Again you shouldn't.
Dependency injection is the way to go.
To access a global variable from within a function, use the global keyword. For example, to access $DB_SETTINGS from Database::connect(), you could do:
public function connect() {
global $DB_SETTINGS;
...
The array would then be accessible inside that function.
As for globally accessible classes, they are automatically just that. Defining a class makes it available anywhere.