PHP Undefined variable in functions and included scripts - php

I've read a LOT of things about this problem, however I still cannot fix it.
In my functions file I declare a variable with a value like so:
$px_host = "localhost";
And I have a database query function like so:
function dbQuery($database, $reqquery){
if(!$connect = mysql_connect($px_host, $px_dbuser, $px_dbpass)){
exit("Error - cannot connect to MySQL server - " . mysql_error());
}
if(!$database = mysql_select_db($database)){
exit("Error - cannot select database - " . mysql_error());
}
if(!$query = mysql_query($reqquery)){
exit("Error - query error.");
}
return $query;
}
And whenever I try and run the function, I get an 'Undefined Variable' error. I've tried setting the variable to global, however it still says it's undefined. They are in the same file and the variable is defined and set before the function.
(I'm bad at explaining this so try and work round it)
The file which contains dbQuery() is included in another file. In the other file, there is a function which uses dbQuery() to get certain information. Is it possible that because it's being initially run from the first file, the variable is outside the scope?

In your specific case you should declare global within function all variables outside the function. So
function dbQuery($database, $reqquery){
global $px_host,$px_dbuser,$px_dbpass;
// rest of function
}
But your code can be improved: You should define constants at the beginning of your script
define('DB_HOST','localhost');
define('DB_USER','user');
define('DB_PASS','pass');
and use constants inside the function (so no need to declare global, and it's more logic because host, user and pass aren't variable but constants).
You should connect at database only once at the beginning of your flow so the function dbQuery execute only the query (according with the function name).
EDIT for completeness of answer:
As some users say you in other comments, I invite you to read the php doc for mysql_connect and see the red advise:
Use of this extension is discouraged. Instead, the MySQLi or PDO_MySQL extension should be used. See also MySQL: choosing an API guide and related FAQ for more information. Alternatives to this function include:
I'm not here for say you what you MUST do in your project, but read the doc and follow the tipps/suggestions is essential for the success of your project. :)

It's getting late, so this is only a partial answer.
Another approach you could take is to pass the database instance into your helper function, thus resolving the credentials issue.
function dbQuery($database, $reqquery)
{
if (false !== ($query = mysql_query($reqquery, $database))) {
exit("Error - query error.");
}
return $query;
}
Now this function receives its dependency via the arguments and is also a lot shorter and doesn't connect / query / disconnect every time.
The remaining code has to be written elsewhere; if you require a database at every page, you can write this pretty high up the chain:
if (false === ($connect = mysql_connect($px_host, $px_dbuser, $px_dbpass))) {
exit("Error - cannot connect to MySQL server - " . mysql_error());
}
if (false === mysql_select_db($database)) {
exit("Error - cannot select database - " . mysql_error());
}
Then you pass $connect around wherever it's required.
$res = dbQuery($connect, 'SELECT "hello world"');
Of course, mysql_connect and friends use implied connections, so you technically don't need to pass it around anyway; it's a good pattern nonetheless.
Last but not least
Learn how to use PDO and revel in the magical world of OOP ;-)

If you set the variable global, you will need to set it global in the function as well. In this case:
$px_host = "localhost";
function dbQuery($database, $reqquery){
global $px_host;
if(!$connect = mysql_connect($px_host, $px_dbuser, $px_dbpass)){
exit("Error - cannot connect to MySQL server - " . mysql_error());
}
if(!$database = mysql_select_db($database)){
exit("Error - cannot select database - " . mysql_error());
}
if(!$query = mysql_query($reqquery)){
exit("Error - query error.");
}
return $query;
}
This should fix this problem.

Related

Internal Server Error with linking database in PHP

I have a database that I want to use to make an array for an app I'm working on in Xcode. I'm following a tutorial I found on the internet here, and I followed the instructions, but my page is displaying an Internal Server Error. I am assuming that I didn't correctly change the info in the following code. Also, my web host uses MYSQL not MYSQLite, so I'm not sure what to change the "new mysqli" to in the code. For obvious reasons I omitted the database info. The database has one table named "descriptions" and the columns are labeled 1-50 with different values assigned.
<?php
class RedeemAPI {
private $db;
// Constructor - open DB connection
function __construct() {
$this->db = new mysqli('hostname', 'Username', 'Pass', 'Database Name');
$this->db->autocommit(FALSE);
}
// Destructor - close DB connection
function __destruct() {
$this->db->close();
}
// Main method to redeem a code
function redeem() {
// Print all codes in database
$stmt = $this->db->prepare('SELECT 1 FROM descriptions');
$stmt->execute();
$stmt->bind_result($1);
while ($stmt->fetch()) {
echo "$1";
}
$stmt->close();
}
}
// This is the first thing that gets called when this page is loaded
// Creates a new instance of the RedeemAPI class and calls the redeem method
$api = new RedeemAPI;
$api->redeem();
?>
PHP variables must start with a letter or _, so your error stems from this statement:
$stmt->bind_result($1);
Change the variable name to something like $col1, or whatever is meaningful.
Also, your select statement will return a single value: 1. You probably mean to do this:
SELECT * FROM descriptions
Two other points:
You shouldn't disable autocommit unless you intend to use transactions.
There's no need to prepare statements with simple queries that don't include untrusted input. You can just use $this->db->query("...")'. You'd need to tweak the other statements to match if you change this.
That internal server error 500 is probably masking some lovely error messages that may help. Switch your debugging on in your php.ini / php5.ini
Add this to your php.ini / php5.ini or just add one of these files to the root of your website should do the trick
display_errors = On
display_startup_errors = On
error_reporting = -1
Second, if your host is not running MYSQLi, then they are running REALLY old php as MYSQLi is standard in php4.1.3 and above
Third, that SQL statement.. its it just some kind of rough example or is that your actual statement? If you are trying to pull off one record it should be
SELECT * FROM tablename.description LIMIT 1
Always best to make your statements very thorough

is my cfg.php connection right?

I have a quick question to you guys, i have created the CFG file which stores my database connection detail in two dimensional array. I then connect it to my PHP class file and make it launch the arrays stated in CFG file. As you can see below in my code:
cfg.php
<?php
$cfg['db']['host'] = 'localhost';
$cfg['db']['user'] = 'root'; //your user name
$cfg['db']['pass'] = ''; //your password
$cfg['db']['db'] = 'db3'; //your database
?>
and my class file :
<?php
require_once(dirname(__FILE__) . 'cfg.php');
class Database {
private $dbConn; //stores the database connection
public function __construct($dbConn)
{
global $cfg;
mysql_connect(DB_HOST,DB_USER,DB_PASSWORD) or die('Could not connect to MySQL server.');
mysql_select_db(DB_DATABASE)or die('Unable to select database: ');
}
}
What i want to ask you is: is this right way of doing this? also what do I need to add in my index to see that it is connected. and the output of the database content. Thank you in advance for taking time and reading my problem. Cheerio.
Edit :
<?php
require_once(dirname(__FILE__) . 'cfg.php');
class Database {
private $dbConn; //stores the database connection
public function __construct($dbConn)
{
global $cfg;
mysqli_connect($cfg['db']['host'], $cfg['db']['user'], $cfg['db']['pass'])
or die('Could not connect to MySQL server.');
mysqli_select_db($dbConn, $cfg['db']['db'])
or die('Unable to select database: ');
}
}
Does this looks better now? If yes. How do i connect it with the index.php file where my forms will be stored. say to output the message of (connected to database). Thank you.
EDIT: changed to mysqli and now when selecting the database it states that i am missing the database name. Not sure where to put that and how to alter it. Thank you.
EDIT: I am on my way to create functions for 'Select' 'Insert' and 'Delete' . If any of you can point me do a great source of information which will help me in my research it will be most appreciated.
You are using constants instead of the actual values from your config in your mysql_connect() function, so that wouldn't work. You would need to do it this way:
mysql_connect($cfg['db']['host'], $cfg['db']['user'], $cfg['db']['pass'])
Aside from that and OO paradigms, it would probably be better if you used PHP's mysqli (as stated here) or PDO, as PHP's mysql_ is pretty outdated.
No you are not doing it correctly. By using this line
require_once(dirname(__FILE__) . 'cfg.php');
in your class file you have introduced a somewhat tight coupling to the config file and you have made it hard to swap it out for other credentials. I.e. you will have to change the file with the Database class in it to change the credentials. So start by dropping that include there.
Another thing you do is using the global keyword which is as far from OOP as you could possibly get. Inject the information the class needs instead.
Also you are using the ancient, deprecated and soon to be removed mysql_* API. You are also calling the execution of your script of something fails (or die()) which makes it impossible to integrate your code in a project and also makes it impossible to correctly handle errors (i.e. custom error page).
When upgrading to a better database API (e.g. PDO) you even don't have the need anymore to use a database class at all.
The above would simply look something like the following:
bootstrap.php
try {
$dbConnection = new \PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $e) {
// nicely handle error here
}
Alternatively you could implement lazy loading for the database connection depending on your requirements.
As you can see now there is no need for an external config file (you can just change the credentials here in the bootstrap file) and there is no need for a database class.

Get actual opened db connection

How can I check if a db-connection is open in PHP?
How can I get a reference to this connection?
How can I determine if it is MySQL, Postgres or something else?
Ideally you would know the variable the connection is saved into. Without this it becomes a hassle to find it. It means you would have to loop through every variable and test each one, but doing this for any reason can be a pain because it wont find variables outside of the current scope. You can loop the current variables using:
foreach(get_defined_vars() as $x){
// Code
}
To check if a variable is a valid connection you can use the below code, it should return an integer:
if(mysql_thread_id($connection){
// Connection exists
}
Once you know its a connection you can use the following to return the type of connection, eg, mysql.
echo get_resource_type($connection);
You'd have to iterate over every defined variable and figure out if it's a resource handle or not. Try get_defined_vars().
Probably the best solution to the problem is to not lose track of the DB connection in the first place.
Consider integrating an ORM into your project such as Doctrine or Propel, or if you want something a little more lightweight, consider a DBAL such as Zend_Db. All of these solutions encapsulate the database connections in class instances, ensuring that they are always available to your code if necessary.
In general terms, I don't think it's really possible, not at least with some sort of complicate workaround. You can, for instance, loop through all defined variables:
foreach(get_defined_vars() as $variable){
if( is_resource($variable) && get_resource_type($variable)=='mysql link' ){
// Found a connection!
var_dump($variable);
}
}
Though, in fact, a connection remains available even if assigned to a local variable out of current scope:
function foo(){
$conn = mysql_connect('localhost', 'test', 'test');
}
foo();
$res = mysql_query('SELECT NOW() AS what_is_the_time');
if( $row = mysql_fetch_assoc($res) ){
var_dump($row);
}
The problem is that PHP doesn't really care about variables when talking about connections:
// One connection and zero variables!
mysql_connect('localhost', 'test', 'test');
$res = mysql_query('SELECT NOW() AS what_is_the_time');
if( $row = mysql_fetch_assoc($res) ){
var_dump($row);
}
You can try and find information about current connection:
var_dump(mysql_thread_id());
// int(2696)
... though many of the functions will just attempt to stablish a new connection if there isn't one so must take care of warnings...:
Warning: mysql_thread_id(): Access denied for user ''#'localhost' (using password: NO)
bool(false)
... unless your configuration actually allows a succesful credential-less connnection attempt.
I'm pretty sure that, whatever you want to do, can be done in an entirely different way :)

PHP, Variable Scope Question

My question is I am using the variable $db in my general script code and within one of my functions. It's purpose is to be the variable that is used for MySQL connections. I have a need inside a function to write some data to the database. In my script I cannot assume that an existing db connection will be open so I open a new one and close it before the function exits. Ever since doing this I am getting an error after the script runs saying the MySQL reference is bad / doesn't exist.
The only thing I can pin it to is in my core code I use the variable $db as the variable name for database connection. I also use the same variable in the function. I did not imagine this would be a problem because I do not use global in front of $db in the function. This should mean the $db I reference in my function is in the functions private scope but it seems to be closing the public $db's connection.
Any thoughts?
Fragments of my code are:
database.php
db_connect()
{
// open mysql db connection and return it;
}
db_close( &$db )
{
// close the passed by reference db connection
}
api.php
api_verify( $keyid, $userid, $key )
{
// open a new db connection
$db = db_connect();
// check for errors. if any errors are found note them in the db
// close the db
db_close($db);
}
main.php
include api.php;
include database.php;
// open a connection to the db
$db = db_connect();
// pull a list of things to process from the db and move through them one at a time
// call api_verify() on each key before working through it's data.
db_close($db)
To manage DB connections, you can create a class rather than a pair of functions. If where you say "MySQL reference", the exact error refers to a "MySQL resource", then you are using the outdated mysql extension and should switch to a more modern extension, such as PDO.
class DBConnection {
protected static $_connections = array(),
static connect($dsn) {
if (!isset(self::$_connections[$dsn])) {
$credentials = self::getCredentials();
/* Create connection. For example: */
try {
self::$_connections[$dsn][0] = new PDO($dsn, $credentials['username'], $credentials['password']);
} catch (PDOException $exc) {
// erase the frame w/ password from call trace to prevent leak.
throw new PDOException($exc->getMessage(), $exc->getCode());
}
/* End create connection example */
self::$_connections[$dsn][0]->dsn = $dsn;
}
++self::$_connections[$dsn]['count'];
return self::$_connections[$dsn][0];
}
static close($db) {
if (isset(self::$_connections[$db->dsn])) {
if (--(self::$_connections[$db->dsn]['count']) < 1) {
unset(self::$_connections[$db->dsn]);
}
}
}
static getCredentials() {
/* credentials can be stored in configuration file or script, in this method, or some other approach of your own devising */
}
}
Note that this isn't exactly OOP (it is, but only in a technical sense). The above doesn't lend itself well to unit testing. If you want a more OO approach (which will be more amenable to unit testing), extend or wrap PDO. Using dependency injection can also help with the coupling issues of the above.
I assume you are opening a connection to the same database with the same username/password at each of the places you call db_connect. When doing so,unless your db_connect explicitly specifies, that you are creating a new link, it will return an already opened link.If that link is then closed using db_close(), it will also close the other connection, since the link is the same. If you are using mysql_connect to connect to the database, it takes an argument called new link
new_link
If a second call is made to mysql_connect() with the same arguments, no new link will be established, but instead, the link identifier of the already opened link will be returned. The new_link parameter modifies this behavior and makes mysql_connect() always open a new link, even if mysql_connect() was called before with the same parameters. In SQL safe mode, this parameter is ignored.
Refer to http://php.net/manual/en/function.mysql-connect.php
I'm not sure if this is the issue you are facing. Hope it helps.
I would assume what is happening is the connect cancels out because there already is a connection, and then the close ends the current connection.
I would recommend either A) start a connection at the beginning of the file, and just know it's always there (what I do); or B) check the to see if the $db variable is set, if not then create the connection, and always end the connection at the end of the file.

Correct way to use mysql database in multiple php files

HI everyone, I was just wondering what the best way to make multiple queries against tables in a mysql databases is. Should I be making a new mysqli object for every different .php page ($mysqli = new mysqli("localhost", "root", "root", "db");)?
Or is there a way to reuse this one time over all php files in my website? Any suggestions would be pretty cool
My vote would be to take an OOP approach. I would have one script that has a DB conn class in it and a method in that class to check if a connection exists and if it does returns the connection object. You could have that db class script referenced [ include_once(); ] on the pages that need to access the database. Then it would be a matter of instantiating the db object, firing the "if-exists" method and if it returns true then just utilize the existing connection within the object.
You could also take a look at utilizing persitent connections to the DB
Persistent connections
However honestly you will be better off in the long run and scalability of your application to handle the db connection management yourself rather then leaving a connection constantly open.
Here is an example of how I would structure that class:
As a note, made by #alex, the mysql_error() should not be echoed to the page in an environment where the display_errors() is set to display all warnings. (e.g error_reporting(E_WARNING);)
class dbconn {
protected $database;
function __construct(){
$this->connect();
}
protected function connect() {
$this->database = mysql_connect('host', 'user', 'pass') or die("<p>Error connecting to the database<br /><strong>" . mysql_error() ."</strong></p>" );
mysql_select_db('databasename') or die("<p>Error selecting the database<br />" . mysql_error() . "</strong></p>");
}
function __destruct(){
mysql_close($this->database);
}
function db(){
if (!isset($this->database)) {
$this->connect();
}
return $this->database;
}
}
You need to create the connection for each page, as each PHP script's lifetime is that of the request.
However, you can place the connection code in one file and then include it from all pages.
You could create a connect.php that validates it's being included by your application, and then creates a DB connection.
You could then include that file at the beginning of your application's init, or the beginning of any independent script that needs a connection =)
Depends on structure of website. If you have:
<a herf='login.php'>login</a>
<a herf='register.php'>register</a>
<a herf='about.php'>about</a>
..., then you'll have to connect in every PHP file, i.e., in login.php, in register.php and in about.php. To make it easier, I would either create config.php file which holds user/pass, or even do like Shad said.
You might also have index.php that contains something like this:
if ( !isset($_GET['module']) ) {
$_GET['module'] = 'about';
}
switch ( $_GET['module'] ) {
default:
case 'about':
include 'about.php';
break;
case 'login':
include 'login.php';
break;
case 'register':
include 'register.php';
break;
}
And HTML code:
<a herf='?module=login'>login</a>
<a herf='?module=register'>register</a>
<a herf='?module=about'>about</a>
In this case you can connect in index.php and then pass the connection to all other involved files.
The 2nd way seems to be more common to me, i.e., it feels more intuitive, more handy and that's what I always do.
I believe that in some cases it might be worthy (performance-wise) to use persistent connections and reserve/release connection when needed (either for transaction or even for single query). For example, simple system that I'm now working with takes 70ms-100ms to generate, and it takes only 40ms-50ms to do SQL queries. If using "single connection" approach, it means that connection is wasted for about 50% of time, while "reserve/release connection when needed" with persistent connections would not have such issue.
One more thing - I would advise you to create some wrapper, i.e., some DBConnection class that connects to DB in constructor and has methods like select() (returns array of data), selectValue() (returns single value, e.g., $db->selectValue('select count(*) from user') would return (int)$numberOfUsers), some exec() for inserts and updates etc.

Categories