php how to change global to dependency injection - php

I am using global variable in my function and after research I found that is a bad practice in PHP instead of that I should use dependency injection but I have problem when changing global to dependency injection. What problem about my code? Thanks for help.
update.php (global)
<?php
include 'db_data.php';
class robot{
public function robotUpdate($conn3){
public function robotUpdate($conn3){
global $nasa;
global $id;
$r_update="UPDATE robot_heartbeat SET last_process_id =$id WHERE nasa_id=$nasa";
$robot_u=$conn3->query($r_update);
}
main.php
<?php
include 'db_data.php';
include 'db_sat.php';
$sql = "SELECT * FROM satellite1.show_activity ";
$result=$conn1->query($sql); //get data from db 1
while($row = $result->fetch_assoc()) {
$sql2 = "INSERT INTO analysis_data.show_activity SET
show_activity_id='".$row["id"]."',
game_show_id='".$row["game_show_id"]."',
account_id='".$row["account_id"]."',
account_code='".$row["account_code"]."',
login_id='".$row["login_id"]."',
$result=$conn3->prepare($sql2); //copy data from db1 into db2
$result->execute();
}
$robot_u = new robot();
$nasa = '2';
$id = $row["id"];
$robot_u->robotUpdate($conn3);
I tried:
update.php (Dependency injection)
<?php
include 'db_data.php';
class robot{
public function robotUpdate($conn3,$nasa,$id){
public function robotUpdate($conn3){
$r_update="UPDATE robot_heartbeat SET last_process_id =$id WHERE nasa_id=$nasa";
$robot_u=$conn3->query($r_update);
}
**main.php**(dependency injection)
$robot_u = new robot();
$robot_u->robotUpdate($conn3,$nasa,$id); //call function first
$nasa = '2'; //inject value
$id = $row["id"];

the value is injected during the function call:
$robot_u->robotUpdate($conn3,$nasa,$id);
So swap them around:
$robot_u = new robot();
$nasa = '2'; //inject value
$id = $row["id"];
$robot_u->robotUpdate($conn3,$nasa,$id);
That said, I noticed you pass a db connection into the class, you might want to consider, if you re-use the same connection over and over in the class to add a constructor
function __construct( $db_connection ) {
$this->db_connection = $db_connection;
}
And create a new instance of the class and pass the db connection there
$robot_u = new robot( $conn3 );
And every time in that class when you need your db connection, use $this->db_connection instead of passing $conn3
Three are lots of free resources around PHP OOP on the internet, would suggest reading some of them :-)

Related

Run MySQL query from external script with Slim Framework

I am using Slim Framework to create REST API.
There is also table in my mysql db where I store information about each request to server.
I have separate file called functions.php where I have log_request() function
require_once('dbconnect.php');
function log_request() {
global $mysqli;
$query = "INSERT INTO log_table (....) VALUES (...) ";
$mysqli->query($query);
}
If I run this script - new record is added to my table. But when I run it using Slim
$app->get('/api/something', function($request, $response) {
require_once('dbconnect.php');
include_once('functions.php');
log_request();
});
I am receiving this error
Call to a member function query() on null
So $mysqli inside log_request() is null - why does it happen?
Because $mysqli; is not in global scoped. You are employing bad practices all across. Refactor your code to take advantage of the advanced Slim PHP features such as Dependency Container or Dependency Injection.
By including the dbconnect file inside another function you have effectively scoped its variables to that block scope. You could simply remove the global keyword and the code should work.
As mentioned by Scriptonomy - in order to use MySQL or to prepare, manage, and inject application dependencies we should use dependency container.
https://www.slimframework.com/docs/v3/concepts/di.html
Step 1
create dependencies.php file
// DIC configuration
$container = $app->getContainer();
$container['db'] = function ($c) {
$host = "localhost";
$user = "user";
$pass = "password";
$db_name = "database_name";
$mysqli = new mysqli($host, $user, $pass, $db_name);
return $mysqli;
};
Step 2
add this code before $app->run();
// Set up dependencies
require __DIR__ . '/../app/dependencies.php';
Step 3
Now you can use mysql (or any other injection)
$app->post('foo', function ($request, $response, $args) {
$res = $this->db->query("SELECT * FROM `app_jobs`");
.......
});

Using config variables inside functions

In the code given below, I am trying to modify it in such a way that the db connection variables are used from a config file. This should make the password more secure as I can restrict the config file's permissions.
Kindly let me know if there is a way by which I can modify the code to get the db variables from another file/config file?
class ActivitycodesCollection {
var $list, $err, $sql;
// --- Private variables for database access
var $_db_host = "######";
var $_db_username = "######";
var $_db_passwd = "######";
var $_db_name = "######";
function query ($where="") {
mysql_pconnect ($this->_db_host, $this->_db_username, $this->_db_passwd);
mysql_select_db ($this->_db_name);
$where = "WHERE " . $where;
$sql = "SELECT * FROM activitycodes $where";
$result = mysql_query ($sql);
$this->err = mysql_error();
$this->sql = $sql;
if (mysql_num_rows($result) > 0) {
while (list($id) = mysql_fetch_array ($result)) {
$this->list[$id] = new activitycodes($id);
}
}
}
}
I tried including the config.ini file in this class/function but it threw an error like
unexpected T_VARIABLE, expecting T_FUNCTION
Your code is hopelessly outdated.
1) Don't use var for properties, use private or protected.
2) Don't use mysql_* functions, use PDO.
3) Don't keep connection details inside the class. Just require PDO connection in constructor.
4) Don't trust any data outside your scope - don't allow just write some untrusted text into your SQL query (you do it by $where variable).
5) Read books. "PHP Objects, Patterns, and Practice" will help you now, and "Clean code" - little bit later.
Example:
class ActivitycodesCollection
{
private $list;
private $PDO;
private $table_name;
public function __construct(\PDO $PDO, $table_name)
{
$this->PDO = $PDO;
$this->table_name = $table_name;
}
public function fetchByParameter($parameter)
{
$query = $this->PDO->prepare("SELECT `id` FROM `{$this->table_name}` WHERE "
." some_field = :parameter");
if (!$query)
{
return false;
}
if (!($query->execute(array(':parameter'=> $parameter))))
{
return false;
}
$results = $query->fetchAll(\PDO::FETCH_ASSOC);
if (!empty($result))
{
foreach ($results as $result)
{
$id = $result['id'];
$this->list[$id] = new ActivityCodes($id);
}
}
}
}
Without seeing the "config" file it's not possible to say how to write a parser for it. A simple solution would be to write some php code which sets the variables - but if you include / require it, the variables will be set in global scope - not within the method. But you could eval(file_get_contents($config_file_path)) - which would set the variables in local scope at the risk of providing a method for code injection.
BTW there are a large number of issues with the code you have provided. Leaving aside the potential risk of SQL injection, if the method parameter is null / blank, then the query will be malformed (consider function query ($where="1"). Relying on specific column ordering is bad practice.
It's also hard to imagine how yo restrict access to this config file when the only practical means would be via suphp or base opendir.
Putting the SQL connection data in a separate files does not increase security at all. Actually, storing them in a file that does not have a .php extension makes it less secure since it might be accessible by a user while the code of a PHP file is not visible to any users. You also cannot use more restrictive permissions on the config file than on your PHP files since whatever user PHP is running as (usually the webserver user) needs to access them.
Simply store the connection data in a PHP file:
<?php
define('DB_HOST', '...');
define('DB_NAME', '...');
define('DB_USER', '...');
define('DB_PASS', '...');
Then include this file (outside your class definition) and use the constants when making the connection.
You can use parse_ini_file in you constructor.
class ActivitycodesCollection {
var $list, $err, $sql;
const CONFIG_FILE = 'config.ini';
// --- Private variables for database access
var $_db_host = ''
var $_db_username = '';
var $_db_passwd = '';
var $_db_name = '';
public function ActivitycodesCollection() {
$config = parse_ini_file(self::CONFIG_FILE);
$this->_db_host = $config['db']['host'];
//etc
}
public function query ($where="") {
mysql_pconnect ($this->_db_host, $this->_db_username, $this->_db_passwd);
mysql_select_db ($this->_db_name);
$where = "WHERE " . $where;
$sql = "SELECT * FROM activitycodes $where";
$result = mysql_query ($sql);
$this->err = mysql_error();
$this->sql = $sql;
if (mysql_num_rows($result) > 0) {
while (list($id) = mysql_fetch_array ($result)) {
$this->list[$id] = new activitycodes($id);
}
}
}
And the ini file should be something like that :
[db]
host = localhost
name = foo
user = bar
pass = baz

Wrapper to Zend_Db is failing

All,
I wrote the following wrapper that extends Zend_Db class to provide db connectivity to my entire application. The db connectivity works fine, but it fails to execute queries when invoked from a different class.
class Testapp_DB extends Zend_Db {
//Declare member variables.
public $db = null;
public $db_host = "";
public $db_database = "";
public $db_username = "";
public $db_password = "";
public function __construct()
{
//Read Database Info from Config File
$this->db_host = Testapp_Registry::get('config')->db->mysql->host;
$this->db_database = Testapp_Registry::get('config')->db->mysql->dbname;
$this->db_username = Testapp_Registry::get('config')->db->mysql->username;
$this->db_password = Testapp_Registry::get('config')->db->mysql->password;
$db = Zend_Db::factory('Mysqli', array(
'host' => $this->db_host,
'username' => $this->db_username,
'password' => $this->db_password,
'dbname' => $this->db_database
));
$db->getConnection(); //Works fine
$this->db = $db;
}
}
Trying to execute query in a PHP file that includes Testapp_DB - fails..
<?php
$db = new Testapp_DB();
print_r($db); //I can see the DB object here
$sql = 'SELECT * FROM tb_Log';
$result = $db->fetchAll($sql, 2); //This method fails.. Don't know why. Any ideas?
print_r($result);
?>
Can someone please explain, why the fetchAll method fails?
Thanks
*Zend_Db* doesnt have any method other than factory().
I dont really get, what you are trying to solve this way, but as far as I can see you need to call query() this way
$db->db->query();
Perhaps instead of using your wrapper, try this:
// Note: change your config to have a 'params' entry
$db = Zend_Db::factory(Testapp_Registry::get('config')->db->mysql);
Zend_Db_Table_Abstract::setDefaultAdapter($db);
Zend_Registry::set('database', $db);
// in your config
...mysql.params.host = ...
...mysql.params.dbname = ...
...mysql.params.username = ...
...mysql.params.password = ...
Then, your Zend_Db_Table objects will have connectivity, and in addition you can grab the connection using Zend_Registry::get('database'). And, you'll make only one database connection once per request.
Try to create a SQL file like schema.mysql.sql,
then test it on phpMyAdmin and when it's free of bugs run this code:
$bootstrap = $application->getBootstrap();
$bootstrap->bootstrap(‘db’);
$config = $bootstrap->getResource(‘db’)->getConfig();
$runCommand = “mysql -h “.$config["host"].” -P “.$config["port"].” -u’”.$config["username"].”‘ -p’”.$config["password"].”‘ “.$config["dbname"].” < “.dirname(__FILE__) . ‘/schema.mysql.sql’;
echo $runCommand;
system($runCommand);
Hope this helps! http://www.unexpectedit.com/zend-php/zend-db-exec-a-sql-file

PHP static $link from db function to db object for transactional queries

I have multiple functions, each running their own SQL query that needs to be inside a transaction... I'm using a static $link to save having to pass around links between functions... for example:
function db() {
$user = "username";
$pass = "password";
$db = "database";
$server = "localhost";
static $link;
if(is_null($link)){
$link = #mysql_connect( $server, $user, $pass );
}
mysql_select_db( $db, $link );
return $link;
}
function transactionWrapper($id){
$link = db();
# Start transaction
mysql_query("SET autocommit=0",$link);
# Get name from other function, but keep this function within the ACID transaction by using the same link
$name = getName($id);
mysql_query("UPDATE tbl2 SET name = '{$name}' WHERE id = '2'",$link);
# Commit transaction
mysql_query("COMMIT",$link);
}
function getName($id){
$link = db();
$result = mysql_query("SELECT name FROM user WHERE id = '{$id}'",$link);
return mysql_result($result,0,0);
}
This works brilliantly at the moment... I can have multiple function calls within different files and not have to pass around the $link.
The problem is now I want to do everything in an object for exception handling and I don't know how to replicate the same static variable upon multiple object instances...
I thought it would be something like:
class db{
static $link;
function db(){
# if link is null, create it with mysql_connect, otherwise return the link
}
}
The problem is... a static variable within a function stays alive for an entire page load, but the static link within an object only exists within the object right?
pconnect isn't an option either :P messy stuff
So how can I get around this? using Objects. I couldn't really find anything after googling for so long so I kind of get the impression I'm doing things a little differently to other people. Inside my transaction I have loads of function calls for various things.
I have alot of code as well... about a year of 60 hrs a week so I didn't have an entire application recode in mind! :P
Thanks, I hope someone can help me and I hope someone else stumbles upon this question in the future if it's answered!
If you declare your object at the start of your script (i.e, as a global), it should be alive for as long as your script runs. This is what my basic SQL class looks like:
class SQL_Connection {
var $connection;
function __construct() {
$this->connection = mysql_pconnect(DB_SERVER, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_TABLE, $this->connection) or die(mysql_error());
}
function query($query){
return mysql_query($query, $this->connection);
}
}
Then somewhere in you script you would do:
$db = new SQL_Connection;

Yet another 'Call to a member function on a non-object' problem

I have a html page that calls a php object to get some data back from the database. It works fine, but the script was getting unwieldy so I decided to break some of it out into a bunch of functions.
So I have the following files:
// htdocs/map.php
<?php
include("config.php");
include("rmap.php");
$id = 1;
$gamenumber = getGameNumber($id);
echo $gamenumber;
?>
// htdocs/config.php
<?php
$_PATHS["base"] = dirname(dirname(__FILE__)) . "\\";
$_PATHS["includes"] = $_PATHS["base"] . "includes\\";
ini_set("include_path", "$_PATHS[includes]");
ini_set("display_errors", "1");
error_reporting(E_ALL);
include("prepend.php");
?>
// includes/prepend.php
<?php
include("session.php");
?>
// includes/session.php
<?php
includes("database.php");
class Session {
function Session() {
}
};
$session = new Session;
?>
// includes/database.php
<?php
include("constants.php");
class Database {
var $connection;
function Database() {
$this->connection = mysql_connect(DB_SERVER, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_NAME, $this->connection) or die(mysql_error());
}
function query($query) {
return mysql_query($query, $this->connection);
}
};
/* Create database connection */
$database = new Database;
?>
// includes/rmap.php
<?php
function getGameNumber($id) {
$query = "SELECT gamenumber FROM account_data WHERE usernum=$id";
$result = $database->query($query); // line 5
return mysql_result($result, 0);
}
?>
And constants has a bunch of defines in it (DB_USER, etc).
So, map.php includes config.php. That in turn includes prepend.php which includes session.php and that includes database.php. map.php also includes rmap.php which tries to use the database object.
The problem is I get a
Fatal error: Call to a member function on a non-object in
C:\Develop\map\includes\rmap.php on line 5
The usual cause of this is that the $database object isn't created/initialised, but if I add code to show which gets called when (via echo "DB connection created"; and echo "using DB connection";) they are called (or at least displayed) in the correct order.
If I add include("database.php") to rmap.php I get errors about redefining the stuff in constants.php. If I use require_once I get the same errors as before.
What am I doing wrong here?
$database is not in the scope of function GetGameNumber.
The easiest, though not necessarily best, solution is
<?php
function getGameNumber($id) {
global $database; // added this
$query = "SELECT gamenumber FROM account_data WHERE usernum=$id";
$result = $database->query($query); // line 5
return mysql_result($result, 0);
}
?>
global is deemed not perfect because it violates the principles of OOP, and is said to have some impact on performance because a global variable and all its members are added to the function's scope. I don't know how much that really affects performance, though.
If you want to get into the issue, I asked a question on how to organize such things a while back and got some good answers and links.
You need to include
global $database;
at the top of getGameNumber(), since $database is defined outside of getGameNumber itself
Your $database varibleis not accessible from the function's scope automatically. You might need to declare it as global $database; in the function.
Scopes in PHP are explained in the documentation: http://de3.php.net/manual/en/language.variables.scope.php
Please also mind that PHP 4and MySQL3 are out of support for a looooong time and might contain security problems and other unfixed issues.

Categories