I'm new to PHP. What I'm trying to achieve is declare multiple DB hosts in an array. Something like below mentioned :
$slaves=array(
array( //Slave 1
'name' => 'slave1',
'server' => '10.10.1.10',
'user' => 'user1',
'password' => 'p#ssuser1'
'port' => '3306'),
array( //Slave 2
'name' => 'slave2',
'server' => '10.10.1.11',
'user' => 'user2',
'password' => 'p#ssuser2'
'port' => '3306'),
)
Once done, I want to make random calls to these slaves i.e., every read request should get served from one of the slaves.
$idx = time() % count($slaves);
$slave = $slaves[$idx];
$con = mysqli_connect($slave['server'], $slave['user'], $slave['password'], "dbname");
But this is not working. If I try to connect these slaves individually, it is working. But not when I declare that in an array. Is there a simple way to make random calls to these slaves ? Please highlight where is the mistake in my code. I have checked few links on web but they use functions and this keyword to make DB calls.
If you require any more information, do let me know.
Thanks in advance.
$slave = $slaves[array_rand($slaves)];
$con = mysqli_connect($slave['server'], $slave['user'], $slave['password'], "dbname");
You should use array_rand function to get random value from array. Check it with this modification.
And you forget to pass database name to connect function.
Related
I have a situation where I'd like to dynamically choose the DB host for postgres DB connections in a Laravel application running in Docker. I don't particularly want to use ENV values or the config/database.php file because it is a one-off query to the external DB that I would prefer to embed in Helper Class.
These actually could go in the .env file:
PSQL_DB_PORT=5432
PSQL_DB_DATABASE=postgres
PSQL_DB_USERNAME=postgres
PSQL_DB_PASSWORD=postgres
and in my helper I can get the hostname for the remote (actually in Docker) postgres server, which will basically be something like:
postgres_index-db1, postgres_index-db2, postgres_index-db3, etc., but I need to fetch that dynamically and store it in a variable $host.
I tried playing around with a thing like this:
DB::disconnect('pgsql');
Config::set("database.connections.pgsql", [
'driver' => 'pgsql',
'host' => $host ,
'port' => env('PSQL_DB_PORT', '5432'),
'database' => env('PSQL_DB_DATABASE'),
'username' => env('PSQL_DB_USERNAME'),
'password' => env('PSQL_DB_PASSWORD'),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
]);
dd(DB::connection('pgsql'));
$query = "select DISTINCT value from maindicomtags where taggroup = 8 and tagelement = 128";
$names = DB::connection('pgsql')->select($query,[]);
and the dd(DB::connection('psql')) (a Laravel dump) statement actually shows the correct config, but when the query tries to execute it must be looking for the pgsql config in my config/database.php file because it throws an error:
Database connection [pgsql] not configured
because it must be looking for the config in the config/database.php file, and I removed the definition from there. I want it to use the connection that is defined above.
Is there a a way to do what I am trying to do. I could even just use the connection string for Postgres if that is possible.
Might actually be working because I might have had a typo earlier (e.g. psql vsl pgsql).
Does this seem like an adequate way to make that type of dynamic connection ? It is really just the host that will be different.
Instead of setting your config, just create a custom database connection using factory. The only downside - you will not be able to use Eloquent as it resolves connection by its name defined in configs. Also, avoid using env variables anywhere else than config files - create other config and use it instead. There is quite a chance something could break somewhere else if you change config on the go:
$factory = app(\Illuminate\Database\Connectors\ConnectionFactory::class);
$db = $factory->make([
'driver' => 'pgsql',
'host' => $host ,
'port' => $port ?? 5432,
'database' => $database,
'username' => $username,
'password' => $password,
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
]);
$names = $db->table('maindicomtags')
->where('taggroup', 8)
->where('tagelement', 128)
->distinct()
->pluck('value');
$db->disconnect();
This question already has answers here:
How to connect to mysql with laravel?
(6 answers)
Closed 8 years ago.
I'm making a PHP application installer (something like Wordpress installation script) and I need to check mysql connection using host name, username, password and database provided by user during installation.
I'm using this code as a Laravel controller method to test connection:
public function TestDatabaseConnection(){
try {
$database_host = Config::get('config.database_host');
$database_name = Config::get('config.database_name');
$database_user = Config::get('config.database_user');
$database_password = Config::get('config.database_password');
$connection = mysqli_connect($database_host,$database_user,$database_password,$database_name);
if (mysqli_connect_errno()){
return false;
} else {
return true;
}
} catch (Exception $e) {
return false;
}
}
This code doesn't seem to properly test the connection. Function return value (true/false) doesn't depend whether user supplies db data at all, or if db data is correct/incorrect..
Fils /app/config/config.php contains the following array:
<?php return array('database_host' => 'localhost', 'database_name' => 'dbasename', 'database_user' => 'dbuser', 'database_password' => 'pass');
and it's being updated via form during installation process.
Is there any way to modify this code or maybe you have some other code suggestions?
Your question is:
How to test MySQL connection in PHP and Laravel?
But then you are setting up a standard PHP MySQLi connection like this:
$connection = mysqli_connect($database_host,$database_user,$database_password,$database_name);
Why would you do that? The whole purpose of using a framework is to work within the framework. And something that encompasses these two basic systems concepts:
Read a configuration file.
Establish a database connection.
Doing those things is something that pretty much every capable—and widely adopted—programming framework should be able to handle within it’s own structure & using it’s own methods.
So that said, looking at the Laravel documentation on “Basic Database Usage” shows the following. This is placed in your DB configuration file located in app/config/database.php.:
'mysql' => array(
'read' => array(
'host' => '192.168.1.1',
),
'write' => array(
'host' => '196.168.1.2'
),
'driver' => 'mysql',
'database' => 'database',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
The example has two distinct DB connections: One for read and the other for write, but that is not how most DB connections for simple projects work. So you can set this instead also using your settings:
'mysql' => array(
'host' => Config::get('config.database_host'),
'driver' => 'mysql',
'database' => Config::get('config.database_name'),
'username' => Config::get('config.database_user'),
'password' => Config::get('config.database_password'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
Then to test that connection, you would just do this:
if(DB::connection()->getDatabaseName())
{
echo "Yes! successfully connected to the DB: " . DB::connection()->getDatabaseName();
}
But that said you are also saying:
I'm making a PHP application installer…
Why reinvent the wheel when PHP build systems such as Phing exist?
You can simply check whether the connection is made or not using this:
if(DB::connection()) {
// connection is made
}
Because you don't need to make connection manually. If the user provided right credentials in the app/config/database.php then the user will be able to query in the database but if you need to check the connection then given code above is able to check because if the connection is not made then an error will be thrown and on a valid connection the Illuminate\Database\MySqlConnection object will be returned. So, in this case it's also possible to use:
if(DB::connection() instanceof Illuminate\Database\MySqlConnection) {
// connection is made
}
So, according to your example of TestDatabaseConnection method you can do something like this:
public function TestDatabaseConnection(){
// Returns Illuminate\Database\MySqlConnection on successful
// connection; otherwise an exception would be thrown if failed
return DB::connection();
}
If you really want to catch the error of laravel db connection failure,
you can define this:
App::error(function(PDOException $exception, $code)
{
die('do what you want here');
});
I defined it inside:
/app/start/global.php
you can define it where ever you like.
I am trying to setup connections to multiple database under the same instance for correlation data analysis
Here is the basic idea of the connection code
$a = array('a','b','c');
$b = array('a','b','c');
foreach($a as $ac){
foreach($b as $bc){
Config::set('database.connections.'.$ac.'_'.$bc, array(
'driver' => 'mysql',
'host' => 'somehost',
'port' => '3306',
'database' => $ac.'_'.$bc,
'username' => 'user',
'password' => 'user',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => ''
));
}
}
There are about 40 different db in that instance, and could change rapidly, so I want to avoid permanently create the connection in the config file and generate the connection on the fly with user input. And from what I gather, the above code should auto append the array to database.connections (see laravel github ), but I am getting this error.
SQLSTATE[HY000] [2002] No such file or directory
if I change database.connections.".$ac.'_'.$bc to database.connections.mysql the code runs okay. So what am I missing here :( , I am calling that piece of code under the constructor of the first controller the input will hit.
Thank you very much for the help in advance
After playing around a bit, found out what's the problem.
After calling the code above in controller,
in model, not only you have to make the initial connection but also you have to include a table in that statement in order to divert the connection to the specific DB, otherwise it will fall back to default connection if you use the way that builder query example from Laravel documentation. So instead of doing
$this->query = DB::connection($ac.'_'.$bc);
$this->query = DB::table('sometable');
do it like
$this->query = DB:connection($ac.'_'.$bc)->table('sometable');
Then connection for $this->query will lock to the new database pointed.
I cannot find any examples, in books or on the web, describing how one would properly initialize an associative array by name only (with empty values) - unless, of course, this IS the proper way(?)
It just feels as though there is another more efficient way to do this:
config.php
class config {
public static $database = array (
'dbdriver' => '',
'dbhost' => '',
'dbname' => '',
'dbuser' => '',
'dbpass' => ''
);
}
// Is this the right way to initialize an Associative Array with blank values?
// I know it works fine, but it just seems ... longer than necessary.
index.php
require config.php
config::$database['dbdriver'] = 'mysql';
config::$database['dbhost'] = 'localhost';
config::$database['dbname'] = 'test_database';
config::$database['dbuser'] = 'testing';
config::$database['dbpass'] = 'P#$$w0rd';
// This code is irrelevant, only to show that the above array NEEDS to have Key
// names, but Values that will be filled in by a user via a form, or whatever.
Any recommendations, suggestions, or direction would be appreciated. Thanks.
What you have is the most clear option.
But you could shorten it using array_fill_keys, like this:
$database = array_fill_keys(
array('dbdriver', 'dbhost', 'dbname', 'dbuser', 'dbpass'), '');
But if the user has to fill the values anyway, you can just leave the array empty, and just provide the example code in index.php. The keys will automatically be added when you assign a value.
First file:
class config {
public static $database = array();
}
Other file:
config::$database = array(
'driver' => 'mysql',
'dbhost' => 'localhost',
'dbname' => 'test_database',
'dbuser' => 'testing',
'dbpass' => 'P#$$w0rd'
);
I got configuration file database.php
<?php defined('_ENGINE') or die('Access Denied'); return array (
'adapter' => 'mysqli',
'params' =>
array (
'host' => 'localhost',
'username' => 'root',
'password' => 'root',
'dbname' => 'db',
'charset' => 'UTF8',
'adapterNamespace' => 'Zend_Db_Adapter',
),
'isDefaultTableAdapter' => true,
'tablePrefix' => 'engine4_',
'tableAdapterClass' => 'Engine_Db_Table',
); ?>
How to get only password from this array?
something like echo $array['password'];
How do I get the array from database.php?
You'll need to include the file and bind the returned value to a variable, such as in the below example.
$db_conf = require ('/path/to/database.php');
$db_conf will contain the data returned by database.php.
Documentation
PHP: include - Manual
How do I read the specific value from my array?
Since you are working with a nested array the solution is not as far away as you might think. First use $a[key] to get to the array stored under params, and then get the value of password from there.
As in the below example.
$password = $array['params']['password'];
Note: The above is, in a logical sense, equivalent to;
$params = $array['params'];
$password = $params['password'];
Documentation
PHP: Arrays - Manual
I tried the above but it's just shouting "Access Denied" in my face, why?
To protect database.php from unintended access it has been protected with a check to see so that it's being used inside of the engine.
The script will die if _ENGINE is not defined.
If you want to use database.php in a script outside of the thought of engine you'll need to define the _ENGINE constant before includeing the file.
define ('_ENGINE', 1);
...
$db_conf = include ('database.php');
echo $array['params']['password'];
Give this a try. :-)