So, simply put, I feel like this code should work. Literally at this moment I am just trying to create a PHP class that takes in some information and runs a command against the database. I know the command works so it's not that, it something to do with the scope of my variables.
I'm new to PHP, and it's been interesting to handle.
<?php
require __DIR__ . '/../bin/composer/vendor/autoload.php';
$cx = new Customer();
$cx->WriteCxToDB();
class Customer {
public $database = new medoo([
'database_type'=>'mysql',
'database_name'=>'dbname',
'server'=>'localhost',
'username'=>'dbusername',
'password'=>'dbpassword',
'charset'=>'utf8'
]);
public function WriteCxToDB(){
global $database;
if($database->has("customer", [
"OR"=>[
"username"=>"cxusername",
"email"=>"email#gmail.com"
]
]))
{
echo "User already exists";
}else{
$database->insert("customer", [
"username"=>"username",
"keyword"=>"keyword",
"email"=>"email#gmail.com",
"phone"=>"444-444-4444",
"first_name"=>"First",
"last_name"=>"Last"
]);
echo "User added";
}
echo "Done";
}
}
?>
I am using composer and medoo to do this database entry. I know the database code works because I've ran it on it's own and it runs fine.
What I'm struggling with the seems to be the variable $database in the code. The function call works if I remove that variable from the mix. I feel like I'm just not understanding where I am supposed to declare the variable / how to reference it from within / outside the function. Thanks.
As suggested in the previous example you should be using something like this and pass a db connection into the class, extending a base class would allow reuse of the db connection:
private $database;
public function __construct($db_connection = null){
//do stuff or set db
$this->database = $this->db_connect;
}
OR make a method in the class to do it
private function db_connect(){
return new medoo([
// required
'database_type' => 'mysql',
'database_name' => 'name',
'server' => 'localhost',
'username' => 'your_username',
'password' => 'your_password',
'charset' => 'utf8',
]);
}
to check consider catching the errors. Using a unique or primary key on the DB would be a safer way of doing this otherwise you have to do validation and searching on the DB. Add the keys and check for duplicate errors.
if($database->error()){
//deal with return or pass to logging
}
The problem here is the use of global scope. Instead of:
global $database;
if($database->has("customer",
use
if($this->database->has("customer",
you could also consider instantiating $database in the constructor, i.e.
private $database;
public function __construct() {
$this->database = new medoo([args....
Related
I have a legacy project, where I have a file with a class that in its construct method makes a connection with a database.
public $mysqli;
public function __construct(){
$this->mysqli = mysqli_connect( "192.168.10.10", "homestead", "secret", "myDatabase" );
}
For now, I would like to make this somewhat flexible and make a config file with an array of values that I would pass to mysqli_connect method. Something like this:
Config file:
$mysqliConfig = [
'192.168.10.10',
'homestead',
'secret',
'myDatabase'
];
And then just require that in the other file and use it in the class constructor of that file:
require_once 'includes/config.php';
class Calculator{
private $mysqli;
public function __construct(){
$this->mysqli = mysqli_connect($mysqliConfig);
}
But that is not working, how should I do that?
You need to make the variables from the config file available to the class.
require_once 'includes/config.php';
class Calculator{
private $mysqli;
public function __construct($mysqliConfig){
$this->mysqli = mysqli_connect($mysqliConfig);
}
}
$cal = new Calculator($mysqliConfig);
As an aside, I would use an associative array for the config to make it more readable.
$mysqliConfig = [
'host' => '192.168.10.10',
'database' => 'homestead',
'user' => 'secret',
'password' => 'myDatabase'
];
// E.g. $mysqliConfig['host']
You can use ... token to unpack the config into the argument list:
$this->mysqli = mysqli_connect(...$mysqliConfig);
What i do is to have a .ini file Advantage is that it returns as a key value association.
save your config details in the .ini file(path/to/config.ini)
In config.ini file,
database_name = mydatabase_name
password = my_password
host = host
system_root = system_root
other_details = other_details
Then on your calculator class, do
<?php
$currentConfig = parse_ini_file(path/to/config/config.ini);
print_r($currentConfig); # prints the entire parsed .ini file
print($currentConfig ['database_name ']); #prints "mydatabase_name"
?>
I'm trying to use flight PHP framework for routing and medoo framework for database usage.
//connect database
$database = new medoo([
'database_type' => 'sqlite',
'database_file' => 'db.sqlite'
]);
//my function
function database($database){
$database->insert("ppl", [
"fn" => "joe","ln"=>"doe"]);
}
//
Flight::route('/add/', array(database($database)));
How to invoke my function with argument from this place:
Flight::route('/add/','database')
Tried different variants but getting errors.
I don't know medoo or flight, but you might be able to use an anonymous function with use:
Flight::route('/add/',
function() use($database) {
$database->insert("ppl", ["fn"=>"joe","ln"=>"doe"])
});
I think you need to re-architect this into an OOP style that will make it much easier and modular, but in a crunch if $database is defined in the global scope:
function database() {
$GLOBALS['database']->insert("ppl", ["fn"=>"joe","ln"=>"doe"]);
}
Flight::route('/add/', 'database');
I am trying integrate a way of a user being able to store there configuration settings into a blank PHP file like this:
<?php // Configuration.php
$con = array(
'host' => 'host'
'user' => 'username',
'pass' => 'password',
'name' => 'dbname'
);
?>
What I have tried:
class Configuration{
public $database = require_once 'Configuration.php';
}
$config = new Configuration;
print_r($config->database->con);
Is this possible or not? There will be a display on the Configuration.php page when accessed so I don't want to include the page in the site, only require its properties.
Thanks in advance.
Updated working code for viewers - Use of Class and Constructors by #Yoshi
Config.php -
if(defined('DFfdcxc58xasdGJWdfa5hDFG')): // Random unique security key
return array(
'host' => 'localhost',
'user' => 'bob',
'pass' => '123',
'name' => 'data'
);
endif;
Database Class:
interface Dashboard{
public function initialize($actual);
}
define('DFfdcxc58xasdGJWdfa5hDFG',0); // Random unique security key
class Configuration{
protected $config = require_once('Config.php');
protected $api_key = "Xc4FeSo09PxNcTTd3793XJrIiK";
}
class DashboardSettings{
public $alerts = array();
protected $comments = true;
protected $read_only = false;
protected $safe_mode = false;
}
class Database extends Configuration extends DashboardSettings implements Dashboard{
public function __construct(){
$this->db = mysqli_connect($this->config[0],$this->config[1],$this->config[2],$this->config[3]);
if(mysqli_connect_errno){ array_push($this->alerts, 'Error connecting to Database...'); $this->safe_mode = true; }
}
public function initialize($actual = null){
if($actual != null){
// Handle incomming setting - reference DashboardSettings
} else {
// Handle all settings - reference DashboardSettings
}
}
}
The answer is no. When you assign require_once(); to a variable, the variable turns into a boolean with 1 in case the file was included successfully, or 0 otherwise (useless in require_once() as it returns a fatal error if it fails.
So, doing:
<?php
$hello = require_once("./hello.php");
echo $hello; // Prints 1.
?>
Anyway, if you create a php file that returns something, as for example:
FILE: require.php
<?php
$hello = "HELLO";
return $hello;
?>
In this case, the previous example would be different:
<?php
$hello = require_once("./require.php");
echo $hello; // Prints HELLO.
?>
So, you cannot store the function itself to execute it later, but you can store returned values from the required or included files. Anyway, if you explain better what are you using it for, I maybe able to help you better.
Answer By #David Álvarez
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?
As the title says there is a problem accessing variable (associative array) inside class from included file. Here is the source code both class and include file:
require("applications/cw_database.php");
require("config/dbConfig.php");
require("config/appConfig.php");
class APP_ASSESMENTS
{
private $dbObj;
private $DisplayOutput = "";
public function __construct($PageParams)
{
try
{
$dbObj = new CW_DB($dbConfig['hostname'],$dbConfig['username'],$dbConfig['password'],$dbConfig['name'],$dbConfig['port']);
} catch (Exception $e) {
throw new ErrorException($e);
}
}
...
The other part has nothing to do with $dbConfig.
Also this is the included file (config/dbConfig.php):
/*
Testing configuration for MySQL database
*/
$dbConfig['username'] = "phpcoursework"; // changed on demand
$dbConfig['password'] = "phpcoursework"; // changed on demand
$dbConfig['hostname'] = "localhost"; // changed on demand
$dbConfig['name'] = "students"; // changed on demand
$dbConfig['port'] = 3306; // default for MySQL
First, $dbObj will not automatically assume class member scope, it will create a local copy of CW_DB and discard it when __construct returns. You need to explicitly reference the property;
$this->dbObj = ...
Anyway, global state using global as suggested by others will "work", but if you're using OOP practices you're best not to do that. You can actually return from an include(), so an option would be to do the following:
// your config file dbConfig.php
return array(
'username' => "phpcoursework",
'password' => "phpcoursework",
'hostname' => "localhost",
'name' => "students",
'port' => 3306,
);
And inject it into the object, via constructor or method (here's constructor)
class APP_ASSESMENTS
{
private $dbObj;
public function __construct($dbConfig, $PageParams)
{
$dbObj = new CW_DB($dbConfig['hostname'], $dbConfig['username'],
$dbConfig['password'], $dbConfig['name'], $dbConfig['port']);
// ...
}
}
// include() here, will actually return the array from the config file
$appAssesments = new \APP_ASSESMENTS(include('dbConfig.php'), $PageParams);
It would be recommended that you go another level up: instead, inject the database object itself, taking the dependency out of your APP_ASSESSMENTS class.
(Also, PascalCase is the typical convention of class naming, such as AppAssessments and CwDb)
$dbObj = new CwDb(include('dbConfig.php'));
$appAssessments = new AppAssessments($dbObj, $etc, $etc);
This simple change allows you to remove the dependency from AppAssessments on CwDb. That way, if you extend CwDb for some reason, you can just pass in an instance of the extended class without having to change any code in AppAssessments
You can change the AppAssessments constructor like so:
public function __construct(CwDb $db, $etc, $etc){
$this->db = $db;
// ...
}
This takes advantage of PHPs (limited, albeit still useful) type-hinting, ensuring the first argument is always of the correct type.
This plays into part of the open/closed principle: classes should be open to extension but closed for modification.
Includes are used in the scope of access. So, to access the variables you need to include the files within your class. As earlier mentioned global will let you access variables from another scope too. But global should be used with caution! See the documentation.
See the manual for more information.
Edit: I need to make it clear that globals are never a good alternative for handling these kind of critical variables..
public function __construct($PageParams){
global $dbConfig;
try{
$dbObj = new CW_DB($dbConfig['hostname'],$dbConfig['username'],$dbConfig['password'],$dbConfig['name'],$dbC onfig['port']);
} catch (Exception $e) {
throw new ErrorException($e);
}
}
or you could use $GLOBALS['dbConfig'].