Run MySQL query from external script with Slim Framework - php

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`");
.......
});

Related

php how to change global to dependency injection

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 :-)

Require_once doesn't seem to affect all functions?

Everything was working fine in my little project, until I decided to clean up a little bit and moved database-related php-files to their own folder. Then things went strange.
I am trying to use two functions here:
function getEntries () {
require_once("mysqliVariables.php");
$mysqli = new mysqli($dbHost, $dbUname, $dbPwd, $dbName);
$sql = "statement...";
$result = $mysqli->query($sql) or die($mysqli->error);
echo $dbHost; // prints host
return $result;
}
function getBiggestMonth () {
require_once("mysqliVariables.php");
$mysqli = new mysqli($dbHost, $dbUname, $dbPwd, $dbName);
echo $dbHost; // prints nothing! why?
$sql = "statement...";
$result = $mysqli->query($sql) or die($mysqli->error); // this line does not run, of course.
return $result;
}
I use another function in a different file (and folder) to call these functions, that starts like this:
function listTasks() {
require_once("db/mysqliFunctions.php");
// Get entries using mysqli.
$tasks = getEntries();
echo "<pre>";
var_dump($tasks);
echo "</pre>"; // program works fine this far.
$bm = getBiggestMonth(); // program breaks somehow during this function call.
My variables are in a php-file like so:
<?php
$dbHost = "host";
$dbUname = "username";
$dbPwd = "password";
$dbName = "databasename";
?>
If I switch the funtion's call order, then getBiggestMonth() runs fine and the other one won't. Also, all of this worked fine when all the files were located in the same folder (the functions were then static functions inside a class, but that shouldn't be an issue, the same problem persists here), so I dont understand how possible variable scope can be different here, and require_once should take care of other things. Help?
This is because you are using require_once. It will only include the configuration once. You can change it to use require so that it will work as you expect.
The require_once() statement is identical to require() except PHP will
check if the file has already been included, and if so, not include
(require) it again.
You are using require_once to pull in a file into the scope of the getEntries() function. PHP keeps a record of the files that have been required in so when you then call require_once in getBiggestMonth() it knows it has already been included in getEntries(). Because it has already been included it does not require the file in again so you don't get your variables in your getBiggestMonth() scope.
require_once does not have anything to do with variables it just monitors the files that have been included into the current PHP process.
The echo statement after the return in getEntries() wont obviously work as the function exits after the return.

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