Mysqli connection trying with different users - php

I'm trying to create a PHP class extending mysqli that is capable of connecting with another user if the connection fails. It is probably easier to explain with code:
public function __construct() {
$users = new ArrayObject(self::$user);
$passwords = new ArrayObject(self::$pass);
$itUser = $users->getIterator();
$itPass = $passwords->getIterator();
parent::__construct(self::$host, $itUser->current(), $itPass->current(), self::$prefix.self::$db);
while($this->connect_errno && $itUser->valid()){
$itUser->next();
$itPass->next();
$this->change_user($itUser->current(), $itPass->current(), self::$prefix.self::$db);
}
if($this->connect_errno)
throw new Exception("Error", $this->connect_errno);
}
$user and $pass are static variables containing arrays of users and passwords.
If the first user fails to connect, I try with the next one.
The problem here is with $this->connect_errno. It says it cannot find Mysqli.
Is there any solution to this or should I create a Factory class?

Not sure why it doesn't find the object (hint, anybody?), however you can still use mysqli_error() for error handling, as shown in this article.
while(!mysqli_error($this) && $itUser->valid()) {
// (...)
}
and
if(mysqli_error($this)) {
throw new Exception(mysqli_error($this), mysqli_errno($this));
}

Related

PHP Calling dynamic functions

Im trying to figure out how to call functions based on what a user clicks on a form. But im not sure if im doing it right.
I have a number of classes, lets say 3 for different ways to connect to a site, the user clicks on which one they would like.
FTP
SFTP
SSH
Which i have named 'service' in my code.
I don't want to run a whole bunch of IF statements, i would rather try and build the call dynamically.
What i have at the moment is as follows
$ftp_backup = new FTPBackup;
$sftp_backup = new SFTPBackup;
$ssh_backup = new SSHBackup;
$service = $request->input('service') . '_backup';
$service->testConn($request);
Im getting the following error
Call to a member function testConn() on string
Im not sure im doing this right.
Any help would be greatly appreciated.
Thanks
First of all $service is a string on which You cannot call method, because it is not an object (class instance).
I think it is a great example of where You can use Strategy Pattern which look like that:
class BackupStrategy {
private $strategy = null;
public function __construct($service_name)
{
switch ($service_name) {
case "ftp":
$this->strategy = new FTPBackup();
break;
case "sftp":
$this->strategy = new SFTPBackup();
break;
case "ssh":
$this->strategy = new SSHBackup();
break;
}
}
public function testConn()
{
return $this->strategy->testConn();
}
}
And then in place where You want to call it You call it by:
$service = new BackupStrategy($request->input('service'));
$service->testConn($request);
I suggest You to read about Design Patterns in OOP - it will help You a lot in the future.
How about this:
$ftp_backup = new FTPBackup;
$sftp_backup = new SFTPBackup;
$ssh_backup = new SSHBackup;
$service = $request->input('service') . '_backup';
${$service}->testConn($request);
This is called "Variables variable": http://php.net/manual/en/language.variables.variable.php
// Create class name
$className = $request->get('service') . '_backup';
// Create class instance
$service = new $className();
// Use it as you want
$service->testConn($request);

PHP database class - Managing two connections with different privileges

I'm just trying to master the art of using classes in PHP and have come across a concern.
For security reasons, I sometimes use two database connections in my application; one with read-only privileges and one with full read/write. Unfortunately, I wasn't really thinking about this when I started to build a few classes.
So, I have a database class, which is essentially a pointless PDO wrapper (pointless because PDO is a wrapper), but thought it'd be good practice to write one anyway and I may extend PDO later too. This is what I did:
<?php
class Database {
private $dbh;
public function __construct($accessLevel = NULL, $credentials = NULL) {
if (gettype($credentials) === 'array') {
$dsn = 'mysql:host='.$credentials['dbHost'].';dbname='.$credentials['dbName'];
$options = array (
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
if ($accessLevel == "public") {
$this->dbh = new PDO($dsn, $credentials['publicUser'], $credentials['publicPassword'], $options);
} else if ($accessLevel == "private") {
$this->dbh = new PDO($dsn, $credentials['privateUser'], $credentials['privatePassword'], $options);
}
}
}
// other database functions
}
?>
For a public connection (read/write), I simply used this:
$db = new Database('public', config['dbConfig']);
... or for a private connection (read-only), I used this:
$db = new Database('private', config['dbConfig']);
... and when I wanted to use the connection in another class, I simply injected the connection, like so:
$user = new User($db);
Works fine, but then I realised that I may need two connections inside that class, one for reading only and one for all. So I got a little confused, but had a go regardless. This is what I did:
Instead of calling the class with either of the connections, I called the class twice with both, like so:
$publicDB = new Database('public', $config['db']);
$privateDB = new Database('private', $config['db']);
and then injected both of those to my other class:
$user = new User($publicDB, $privateDB);
Inside this User class, this how I used the two connections:
<?php
class User {
private $dbh;
private $dbhp;
public function __construct($publicDatabase = NULL, $privateDatabase = NULL) {
$this->dbh = $publicDatabase;
$this->dbhp = $privateDatabase;
}
public function doSomething() {
$this->dbh->query("INSERT INTO......");
$this->dbh->execute();
}
public function doSomethingSafely() {
$this->dbhp->query("SELECT * FROM......");
$results = $this->dbhp->resultset();
}
}
?>
Right, this actually works fine but I'm worried it's not the acceptable method or it may cause problems later down the road. I have a few questions:
Is using two connections with different privileges still considered good practice? Even though I'm properly escaping and validating my data and binding the values using PDO?
If yes for above, is there a better way to manage the two connections for using in many classes or is what I have done acceptable?

Use try/catch as if/else?

I have a class that accepts user ID when instantiated. When that ID does not exist in the database, it will throw an exception. Here it is:
class UserModel {
protected $properties = array();
public function __construct($id=null) {
$user = // Database lookup for user with that ID...
if (!$user) {
throw new Exception('User not found.');
}
}
}
My client code looks like this:
try {
$user = new UserModel(123);
} catch (Exception $e) {
$user = new UserModel();
// Assign values to $user->properties and then save...
}
It simply tries to find out if the user exists, otherwise it creates a new one. It works, but I'm not sure if it's proper? If not, please provide a solution.
No this isn't proper, try catch blocks should be used to handle code where anomalous circunstaces could happen. Here you're just checking if the user exists or not so the best way to achieve this is with a simple if else.
from wikipedia definition of programing expception:
"Exception: an abnormal event occurring during the execution of a
routine (that routine is the "recipient" of the exception) during its execution.
Such an abnormal event results from the failure of an operation called by
the routine."
As #VictorEloy and #AIW answered, exceptions are not recommended for flow control.
Complementing, in your case, I would probably stick with a static method for finding existing users that would return an instance of UserModel if it finds, or null in case it does not. This kind of approach is used in some ORM libraries like Active Record from Ruby on Rails and Eloquent from Laravel.
class UserModel {
protected $properties = array();
public static function find($id) {
$user = // Database lookup for user with that ID...
if ($user) {
return new UserModel($user); // ...supposing $user is an array with its properties
} else {
return null;
}
}
public function __construct($properties = array()) {
$this->properties = $properties;
}
}
$user = UserModel::find(5);
if (!$user)
$user = new UserModel();
It is debatable, but I'm going to say this is NOT proper. It has been discussed before. See
Is it "bad" to use try-catch for flow control in .NET?
That seems like a proper behaviour as long as it doesn’t throw when $id is null (that way, you can assume a new one is to be created).
In the case of the code that uses your class, if you’re going to be inserting it with that same ID later, just insert it with that ID to begin with without checking – it could be possible, though unlikely, that something happens between the check and the insertion. (MySQL has ON DUPLICATE KEY UPDATE for that.)

Codeigniter multiple database, conn_id returns object even if connection fails

I have been reading several posts plus the official guides about how to connect more than one database in CI. I currently connect to the default application database using the standard database.php configuration and load the other database on the fly when needed. The main purpose of this part of the app is to have an "import" feature where the users user inputs the foreign database connection data on the fly when requested.
As long as the second database connection data is correctly set, the app works like a breeze. When there's an error in the connection config I didn't find a working method to evaluate that a connection could not be estabilished to the other database.
I found out that I could check if $db->conn_id is false to eventually return an error to the user but for some reasons it returns an object no matter what.
This is a brief example of what I'm doing inside the model:
function plugin_subscribers_import_sfguard($channel_id)
{
// Get the channel object by its ID
$channel = $this->get_channel_by('id',$channel_id);
// Set the preferences for the second database
// from the channel informations we retrieved
$db['hostname'] = $channel->host;
$db['username'] = $channel->user;
$db['password'] = $channel->password;
$db['database'] = $channel->db;
$db['dbdriver'] = "mysql";
$db['pconnect'] = FALSE;
$db['db_debug'] = TRUE;
// Open the connection to the 2nd database
$other_db = $this->load->database($db,TRUE);
if ( ! $other_db->conn_id )
{
// This never gets executed as $other_db->conn_id always
// returns: "resource(34) of type (mysql link)"
return false;
}
else
{
// Execute the rest of the import script
$other_db->select('*');
$other_db->from('sf_guard_user');
$other_db->join('sf_guard_user_profile',
'sf_guard_user_profile.id=sf_guard_user.id',
'inner');
$query = $other_db->get();
}
}
I wonder if there's something I didn't get out of the whole thing or if I'm using the wrong logic to evaluate if the secondary database has a proper connection open.
I also tried to try/catch the connection issue with no success.
Thanks in advance for all the support you can offer.
Federico
It's because by setting the second parameter to TRUE (boolean) the function will return the database object and in the DB.php there is a function DB and the last code block is
function &DB($params = '', $active_record_override = NULL)
{
// ...
$driver = 'CI_DB_'.$params['dbdriver'].'_driver';
$DB = new $driver($params);
if ($DB->autoinit == TRUE)
{
$DB->initialize();
}
if (isset($params['stricton']) && $params['stricton'] == TRUE)
{
$DB->query('SET SESSION sql_mode="STRICT_ALL_TABLES"');
}
return $DB;
}
So, I think, if you call this
$other_db = $this->load->database($db,TRUE);
wiuthout the TRUE
$other_db = $this->load->database($db);
Then it could give you a different result.
Update : if i you want to use
$other_db = $this->load->database($db,TRUE);
then you can also check for a method availability using method_exists function, like
$other_db = $this->load->database($db,TRUE);
if( method_exists( $other_db, 'method_name' ) ) {
// ...
}

php oop and mysql

I need to get data, to check and send to db.
Programming with PHP OOP.
Could you tell me if my class structure is good and how dislpay all data?. Thanks
<?php
class Database{
private $DBhost = 'localhost';
private $DBuser = 'root';
private $DBpass = 'root';
private $DBname = 'blog';
public function connect(){
//Connect to mysql db
}
public function select($rows){
//select data from db
}
public function insert($rows){
//Insert data to db
}
public function delete($rows){
//Delete data from db
}
}
class CheckData{
public $number1;
public $number2;
public function __construct(){
$this->number1 = $_POST['number1'];
$this->number2 = $_POST['number2'];
}
function ISempty(){
if(!empty($this->$number1)){
echo "Not Empty";
$data = new Database();
$data->insert($this->$number1);
}
else{
echo "Empty1";
}
if(!empty($this->$number2)){
echo "Not Empty";
$data = new Database();
$data->insert($this->$number2);
}
else{
echo "Empty2";
}
}
}
class DisplayData{
//How print all data?
function DisplayNumber(){
$data = new Database();
$data->select();
}
}
$check = new CheckData();
$check->ISempty();
$display = new DisplayData()
$display->DisplayNumber();
?>
That's horrible piece of code.
For database communication use PDO. It's not perfect, but it's fine.
Every time you'll need database you'll connect with that db?
Database::insert() etc. would have to be a true magician to guess where its parameter should be inserted
You need a better IDE to show your undefined variables. I use PHPStorm.
You need some dependency injection. Use encapsulation. Just follow SOLID.
Second to last thing, don't echo from within objects. You can't unit test effectively your code that way.
You might also try some TDD.
You're going at things wrong here, I think. What you are constructing is a wrapper around already-existing database functions. Thing is, those functions already defined to do exactly what you want - the object oriented approach here serves no real purpose since it can only connect to one database and the methods are not really well defined and seem to act as pure pass-throughs to the underlying layer.
As others have mentioned, the code you seem to be going at here is not going to suit your purposes. Something like PDO will serve you well and its already built in to PHP. You don't need to re-invent the wheel for such common code as accessing a database.
Learning a few core Object Orientation principles will do you good too - look at encapsulation and code re-use first. They'll help in the future when you have to maintain that code you write!

Categories