OK, I see some similar questions to mine, but their examples all use PHP classes...mine does not. Maybe that's the problem? I shouldn't need classes because my site is exceedingly simple at this point in time.
Anyway, I'm trying to use PDO to connect to a MySQL db. I connect to the db fine in a file called config.php, and include this file in index.php with require_once().
I can successfully query the db from another file called process.php, but the problem is within a function within that file; it seems my DBO object is out of scope within that function.
Here are the relevant code snippets:
index.php
require_once('./lib/config.php');
config.php
// tested and connects fine
$pdo = new PDO('mysql:host=' . $hostname . ';dbname=' . $dbname, $username, $password, array(
PDO::ATTR_PERSISTENT => true
));
process.php
<?php
...
// can call $pdo fine in this file outside of functions
...
function authenticate($u, $p) {
// can't call $pdo in here, error says $pdo is non-object
$que = $pdo->query('select user_id, user_pass from users where user_name = \'' . $u . '\' limit 1');
...
}
?>
By the way, I'm using PDO because I was having similar trouble with mysqli, and am trying to get away from mysql, which is apparently depreciated and discouraged.
EDIT: I should have clarified first based on the number of responses I got on this matter: I did try to pass $pdo in as a param to the function, with no luck or change in the error message.
SOLUTION: OK, apparently the problem was that I needed to add require_once('config.php') in my process.php file as well. Not sure why (wouldn't it already be included when index.php was run first?). Then I was able to successfully pass $pdo in as a param to my function, and voila.
That's pretty basic PHP stuff. Variables inside functions are local variables unless you use the global keyword to load them. I suppose you want this:
function authenticate(PDO $pdo, $u, $p) {
$que = $pdo->query('select user_id, user_pass from users where user_name = \'' . $u . '\' limit 1');
//...
}
Edit: If PHP claims that $pdo is not an object, it's not an object, so it doesn't really matter how it's passed to the function. Inspect the variable right before you call authenticate():
var_dump($pdo);
Without the relevant code there's no way to say why. (Assuming it's true that new PDO succeeds.)
You need to pass the PDO object as a parameter to the authenticate() function:
function authenticate(PDO $pdo, $u, $p) {
// ..as in the question..
}
Oh and you should be using a place holder for that username in the query, not string concatenation which is prone to SQL injection attacks.
because $pdo has been declared outside of the function authenticate it isn't available inside it. You need to either pass $pdo in
function authenticate($u, $p, $pdo) {
$que = $pdo->query('...');
}
or declare it as global inside the function to be able to access it
function authenticate($u, $p) {
global $pdo;
$que = $pdo->query('...');
}
Related
I'm trying to put the following code into a function as I need to use it quite a few times but with one variable changed ($subject) but it doesn't seem to be working. If I remove it from the function and run it, it works fine but as soon as it goes into the function and gets called it breaks so I'm not sure there is anything wrong with the code itself. I'm new to using PHP functions, but do I need to pass in everything or can it access variables outside of the function such as the $connect and $id variables which are defined above?
function count($subject){
$getCount = $connect->prepare('SELECT count(*) FROM entries WHERE uid = :id AND subject = :subject');
$getCount->execute(array(
':id' => $id,
':subject' => $subject
));
$rowCount = $getCount->fetchColumn();
return $rowCount;
}
echo count("English");
$connect is no longer accessible inside the function. A simple, but bad fix would be this:
function count($subject){
global $connect
A better fix would be for you to send in the $connect variable to the function:
function count($subject, $connect){
And change your function calls to
count("The subject", $connect)
I am relatively new to PHP OOP and i know that there are numerous questions here on SO, but none of them seam to be pointing me in the right direction. I have created the class user, and I am calling this in another file.
I am trying to get the method 'reset' to call up 'connect', connect to the mysql db and then query it and set various properties to the row contents.
I am receiving no errors but for some reason it is not feeding the properties any data from the database.
I have tried placing the mySQL connect in the reset method, just to see if the variables cannot be passed between methods. But still no joy.
Can anyone point me in the right direction?
class user(){
public function reset(){
$this->connect();
$sql ='SELECT * FROM users WHERE user_id="'.$user_id.'"' ;
$result = mysqli_query($con,$sql);
while($row = mysqli_fetch_array($result))
{
$this->user_name=$row['dtype'];
$this->user_id=$row['user_id'];
$this->atype=$row['atype'];
$this->user_email=$row['user_email'];
$this->group1=$row['group1'];
$this->group2=$row['group2'];
$this->group3=$row['group3'];
$this->group4=$row['group4'];
$this->group5=$row['group5'];
$this->group6=$row['group6'];
}
// Test that these properties are actually being echoed on initial file... it is
// $this->user_name = "john";
// $this->user_email = "john#gmail.com";
// $this->dtype = "d";
// $this->atype = "f";
}
public function connect(){
//GLOBALS DEFINED IN INDEX.PHP
if ($db_open !== true){
$con=mysqli_connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
// Check connection
if (mysqli_connect_errno())
{
$debug_system .= 'Error on user.php: ' . mysqli_connect_error().'<br\/>';
} else {
$db_open = true;
$debug_system .= 'user.php: user details grab successful. <br\/>';
}
}
}
}
If you are relatively new to PHP OOP, it is strongly recommended not to mess with awful mysqli API but learn quite sensible PDO first, and only then, making yourself familiar with either OOP and prepared statements, you may turn to mysqli.
Nevertheless, there shouldn't be no function connect() in the class user. You have to have a distinct db handling class, which instance have to be passed in constructor of user class
The problem lies in this line:
$sql ='SELECT * FROM users WHERE user_id="'.$user_id.'"' ;
At no point do you actually define $user_id. Presumably you actually mean $this->user_id.
$sql ='SELECT * FROM users WHERE user_id="'.$this->user_id.'"' ;
Better still would be to make full use of parameterized queries, which might look like this:
$sql ='SELECT * FROM users WHERE user_id=?' ;
You would then prepare the statement and bind the user ID, then execute the query:
$stmt = mysqli_prepare($sql);
mysqli_stmt_bind_param($stmt, $this->user_id);
mysqli_stmt_execute($stmt);
And then fetch the results:
while($row = mysqli_stmt_fetch($result))
As you can see, there is a whole load more to modern MySQL libraries. I'd advise you to do more research into how MySQLi and parameterized queries work (and perhaps PDO as well: it's a superior library) before you use them further. It will be worth the effort.
In a file, I connect to the database (using PDO) and the resulting connection is called $db, so that queries I run would be something like
$db->query("SELECT money FROM bank_accounts");
However, if I put that line in a function, $db isn't defined so it doesn't work.
Obviously reconnecting to the database in each function isn't the best way to accomplish db calls in a function so how would I accomplish something like
function stealMoney($acctID) {
$db->query("SELECT money FROM bank_accounts WHERE accountID = $acctID");
}
You need to use $db in a function.
And its not defined in the function, so definitely, $db is inaccessible/undefined to the function body.
There are two ways to deal it:
1) Pass $db as an argument to the function.
So, the function body becomes:
function stealMoney($acctID, $db = NULL) {
$db->query("SELECT money FROM bank_accounts WHERE accountID = $acctID");
}
And the function call:
stealMoney($acctID, $db);
2) Use global:
In this case, you can use $db as a global.
So, the function body becomes:
function stealMoney($acctID) {
global $db;
$db->query("SELECT money FROM bank_accounts WHERE accountID = $acctID");
So that, your function will read this variable from outside and can access it.
I have come to the conclusion that using mysqli in an OO approach is better than a procedural approach. (Source: Why is object oriented PHP with mysqli better than the procedural approach?). But I'm not quite sure if what I am doing is really all that more efficient than what I was doing before.
I have a function that runs sql queries. This is what my block of code looked like:
Database connection:
function connectDB(){
$con = mysqli_connect(server, username, password, database);
return $con;
}
Query function:
function executeQuery($payload){
$con = connectDB;
$result = mysqli_query($con, $payload);
return $result;
}
As you can see, that's not very efficient because I'm creating a new database connection every time executeQuery is called. So I figured I'd try it using OOP.
Database connection (OOP):
function connectDB(){
$con = new mysqli(server, username, password, database);
return $con;
}
Database query (OOP):
function executeQuery($payload){
$con = connectDB();
$result = $con->query($payload);
return $result;
}
Now to me, it seems that I am obviously doing something wrong. Each time a query is called I am re-instantiating the mysqli class and I assume that mean's that I am making another database connection.
So how do I do this properly and efficiently?
So how do I do this properly and efficiently?
This really has nothing to do with using MySQLi in a procedural versus OOP way.
What this has to do with is the following line:
$con = connectDB();
This will recreate the database connection on every query. Which, as you noted, is not efficient.
There are many ways to solve this. For example:
Use the mysqli class directly.
Pass $con to executeQuery() (Dependency Injection)
Create a DB class with both connectDB() and executeQuery().
I usually use mysqli directly as I see no reason to wrap the native class. I create the connection object globally (in a config file) and use Dependency Injection when other objects/functions need it.
Although your procedural approach can be solved pretty easily
function connectDB(){
return mysqli_connect(server, username, password, database);
}
function executeQuery($payload){
static $con;
id (!$con)
{
$con = connectDB();
}
return $con->query($payload);
}
an OOP approach would be indeed better. I am not an OOP pro, but you can take a look at my approach which at least using encapsulation to hide all the dirty job inside and provide concise methods to get the data already in desired format like this:
// to get a username
$name = $db->getOne('SELECT name FROM table WHERE id = ?i',$_GET['id']);
// to get an array of data
$data = $db->getAll("SELECT * FROM ?n WHERE mod=?s LIMIT ?i",$table,$mod,$limit);
// to get an array indexed by id field
$data = $db->getInd('id','SELECT * FROM ?n WHERE id IN ?a','table', array(1,2));
// to get a single dimensional array
$ids = $db->getCol("SELECT id FROM tags WHERE tagname = ?s",$tag);
// a simple code for the complex INSERT
$data = array('offers_in' => $in, 'offers_out' => $out);
$sql = "INSERT INTO stats SET pid=?i,dt=CURDATE(),?u ON DUPLICATE KEY UPDATE ?u";
$db->query($sql,$pid,$data,$data);
As a solution for your exact problem : "You do not want to instantiate a new MySQL connection for each time a query is executed" ,
Well, we can think about the following :
You need to make your connection variable ($con) in GLOBAL scope, such that when accessed through any function you can grab THAT variable you set before, not instantiate a new one.
we can do this using keyword "global" , as following :
The connection function :
function &connectDB(){
global $con;
if(empty($con)) {
$con = new mysqli(server, username, password, database);
}
return $con;
}
And for more performance , we avoid cloning/copying the connection variable/resource by using reference function ( &connectDB ),
Query Execution function
Now we've set the connection function in a flexible way , to set the queryExecution function , we can use more than one solution :
First solution :
function executeQuery($payload){
$con = &connectDB(); // do not forget the () , it's good practice
return $con->query($payload);
}
In this solution we made use of "reference" , so the expression :
$con = &connectDB();
will set the variable $con as a reference/shortcut for global $con (i.e : just pointing to the global variable $con)
or
Second solution :
function executeQuery($payload){
global $con;
return $con->query($payload);
}
but for the second solution : Function "connectDB()" MUST be called at least once before any calling to "executeQuery()", In order to make sure that there a connection has been established with the database,
Keep in mind that, according to this solution , calling "connectDB()" more than once will not create more than one connection , once it is called , connection is created, if called again it will return the PREVIOUSLY created connection.
Hope it helps :)
by the way : stay with the OOP approach for database connection , it has much more benefits over the procedural ways,
& I recommend using PDO, it is much more portable.
I am trying to make a function to pull a page's content from a MySQL table using a PDO Prepare statement. My code works just fine outside of the function I defined, but no matter what I do it will not work within the function - I receive the following error:
Fatal error: Call to a member function prepare() on a non-object in /home/tappess1/public_html/pages/stations.php on line 6
Here is my PHP:
function getPageContent($page) {
$st = $db->prepare("SELECT * FROM content WHERE title LIKE ?");
$st->execute(array($page));
$pageContent = $st->fetch();
$text = wordwrap($pageContent['content'], 100, "\n");
$tabs = 4;
$text = str_repeat(chr(9), $tabs) . str_replace(chr(10), chr(10) . str_repeat(chr(9), $tabs), $text);
echo $text;
}
and then
<?php getPageContent(Main);?>
I have even tried using a query instead of prepare statement, simply calling getPageContent() and I receive the same error.
Thanks!
You are trying to access the variable $db which is outside your function's scope.
Either re-initialize your database within the function $db = new PDO...., or - probably better and easier in your case - import the global variable:
function getPageContent($page) {
global $db;
Where and how to best store the global database object is subject of a lot of discussion. If you want to get into it, here is one place to start (there are many others on SO, too). But if you're just getting into PHP, I'd say using the global variable is fine.
The variable $db is not known within your function.