This question already has answers here:
mysqli + xdebug breakpoint after closing statement result in many warnings
(6 answers)
Closed 2 years ago.
Im' getting this warning "property access is not allowed yet" when trying to close mysqli connection. WHY?
$mysqli = new mysqli ( $database ["dbUri"], $database ["dbUserName"], $database ["dbPassword"], $database ["dbSchema"], $database ["dbPort"] );
$mysqli->autocommit(FALSE);
$con = $mysqli;
$rowsAffected = /* completes insert using $con */;
if ($rowsAffected==0) {
throw new Exception("Insert of new record failed");
}
$insertId = $con->insert_id;
$con->commit();
$con->close();
BTW, the insert is successful and I have the correct value in $insertId. Commit works well too, but it's the close that triggers the warning.
I hid the code in /* completes insert using $con */ section as it is long and irrelevant (the sql works). So unless you think it is relevant I only included the rest.
I looked at similar questions but other posts refer to the connection not being established. However, my connection works. PLEASE see the point about "insert is successful".
As far as my analysis of this intermittent problem has concluded (at least in my case), this is some kind of bug in either the mysqli extension or the PHP debugger (XDebug), since it only happens when I breakpoint/single-step the program, but not when simply running the same code without breakpointing/single-stepping any code before the page rendering has completed.
Does it still happen for you if you don't breakpoint or single-step any code before the page rendering is complete?
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am trying to learn how to use PHP PDO as Object Oriented Programming.
I have tried following these two tutorials:
http://culttt.com/2012/10/01/roll-your-own-pdo-php-class/
http://culttt.com/2012/09/24/prevent-php-sql-injection-with-pdo-prepared-statements/
but I can't get anything on either of them to work.
The second one gives a download link to a pre-written wrapper class class.db.php from http://www.imavex.com/php-pdo-wrapper-class/
using this pre-written wrapper class and trying something as simple as this tutorial.php (credentials changed):
// Include the database class
include("class.db.php");
// Connect to database
$db = new db("mysql:host=localhost;dbname=my-db-name", "my-username", "my-password");
$results = $db->select("ad_publication");
print_r($results);
The above shows a blank page.
I know there is nothing wrong with the pre-written class and the text of the above example as it was copied directly out of the tutorial and the comments are full of thanks and praise.
I know there is nothign wrong with my credentials as this works fine:
try
{
$pdo = new PDO('mysql:host=localhost;dbname=my-db-name', 'my-username', 'my-password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec('SET NAMES "utf8"');
$output = 'Connection Successful';
echo $output;
}
catch (PDOException $e)
{
$output = 'Unable to connect to the database server.' . $e->getMessage();
echo $output;
exit();
}
And outputs Connection Successful
My Server is running PHP 5.5 and the table used in the example above is an InnoDB table.
When I run the example select statement my error logs show:
PHP Notice: Undefined variable: GhG678 in /var/www/vhosts/mywebsite.com.au/httpdocs/booking/tutorial.php on line 7
line 7:
$db = new db("mysql:host=localhost;dbname=my-db-name", "my-username", "my-password");
PHP Warning: Creating default object from empty value in /var/www/vhosts/mywebsite.com.au/httpdocs/booking/class.db.php on line 18
line 18:
$this->error = $e->getMessage(); // (from public function __construct)`
PHP Fatal error: Call to a member function select() on a non-object in /var/www/vhosts/mywebsite.com.au/httpdocs/booking/tutorial.php on line 9
line 9:
$results = $db->select("ad_publication"); // (an existing table with data in it)
I just can't see what I could be doing wrong especially as the wrapper class was not written by me and no-one else is complaining about it (heaps of praise) and the contents of tutorial.php were copied directly from the page with only the table name changed.
Like I say, using the PDO connection and doing normal PDO queries without the wrapper class, work fine.
Can anyone here see anything that could be going wrong or know of anything that I should look at?
I'm not sure why I copped a -1 for that question??
I thought it was very complete.
Anyway, thanks to #Sean for providing the clue to the answer.
My password does in fact have a $ character in it.
The connection code of mine that does work (as shown above) is:
$pdo = new PDO('mysql:host=localhost;dbname=my-db-name', 'my-username', 'my-password');
Their code that I was using is:
$pdo = new PDO("mysql:host=localhost;dbname=my-db-name", "my-username", "my-password");
changing the " characters to ' worked straight away.
The password was auto-generated by my hosts (Plesk) and I don't know enough about PHP to know that there is a difference between ' and ". I've never known why some people use one and some use the other. Seems I still have a lot to learn.
#Sean, because you didn't put it as a reply, I couldn't choose your suggestions as the answer, so I don't know how to give you the points, but thank you very much for steering me in the right direction.
I have several stored procedures that I am calling via PDO in PHP. I was hoping to be able to handle errors by performing a ROLLBACK, but I still want to be able to use PHP to retrieve and handle the last error in the procedure. I have tryed using PDO::errorCode() and PDO::errorInfo(), but that does seem to be a legitimate solution, I think because I am already handling the errors in my stored procedures.
When I call one of the stored procedures via command line and then call SHOW ERRORS I get a nice result set with the error status, code and message, but if I call SHOW ERRORS in PDO after executing the stored procedure, I get no results. I also get no result from SHOW ERRORS in command line if I call show errors inside the stored procedure.
I would use GET DIAGNOSTICS, but the MySQL server I am developing for is on a hosted cPanel that I don't have control over updating and it is version 5.5.
Is there some other option I could use or another route I should be taking?
Like I said, I have several stored procedures I want to handle errors, but I can't even get this to work on a simple stored procedure:
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
END;
SELECT *
FROM bunnies;
END
Update: My PHP code was in an object, so I copied and simplified the code to post per Barmar's request and when I tried the simplified code, I found that SHOW ERRORS does indeed work with PDO when prepared and executed after the function is prepared and executed.
My object was a little complicated (I wrote it a while back before I knew much about PHP OOP), so I simplified it as well and now it works! I think the connection was being closed in between calls and now that the code is simpler, I am having no problems with calling SHOW ERRORS in it.
Here's the simplified PHP code I used to test, in case anyone has had issues getting this to work:
$host = '***';
$user = '***';
$pass = '***';
$schema = '***';
$connection = new PDO('mysql:host=' . $host . ';dbname=' . $schema . ';', $user, $pass);
$statement = $connection->prepare('CALL test()');
$statement->execute();
$statement = $connection->prepare('SHOW ERRORS');
$statement->execute();
echo var_dump($statement->fetchAll());
$statement = null;
$statement = null;
$connection = null;
Make sure you use the same PDO connection object to execute the original queries and to retrieve the errors. Each connection has its own error state.
Can you still use a mysqli_result object after you have closed the mysqli connection that produced it? For instance, I am creating a PHP object with a method that opens a mysqli connection, performs a query, stores the result into a parameter, then closes the connection. Will this work or should I fetch_all() the result into an array and then close the connection?
I can find nothing in the documentation or elsewhere online that answers this question. Perhaps that is because it is mind-boggingly obvious to everyone else but it is not to me.
Yes. By default, mysqli runs queries with the option MYSQLI_STORE_RESULT, which means it copies the result set to the client (into the memory of the PHP driver). Therefore when you "fetch" from a mysqli result, you're really just looping over the result set that has already been completely fetched from the MySQL Server. And if you close the connection, the driver keeps that data.
Here's a quick code example to demonstrate:
$con = new mysqli(...);
sleep(10);
/* go run SHOW PROCESSLIST in a MySQL shell to see the connection */
$sql = "SELECT SLEEP(10) FROM test.foo ";
$result = $con->query($sql);
/* observe the query running in SHOW PROCESSLIST */
$con->close();
sleep(10);
/* now go look at SHOW PROCESSLIST to verify the connection is gone */
print_r($result->fetch_all());
/* Hey! I got the data anyway */
I am writing an Android app which communicates with a PHP backend. The backend db is SQLite 3. The problem is, I am getting this error intermittently PHP Warning: SQLite3::prepare(): Unable to prepare statement: 5, database is locked. I am opening a connection to the database in each PHP file and closing it when the script finishes. I think the problem is that one script locked the database file while writing to it and the second script was trying to access it, which failed. One way of avoiding this would be to share a connection between all of the php scripts. I was wondering if there is any other way of avoiding this?
Edit:
This is the first file:
<?php
$first = SQLite3::escapeString($_GET['first']);
$last = SQLite3::escapeString($_GET['last']);
$user = SQLite3::escapeString($_GET['user']);
$db = new SQLite3("database.db");
$insert = $db->prepare('INSERT INTO users VALUES(NULL,:user,:first,:last, 0 ,datetime())');
$insert->bindParam(':user', $user, SQLITE3_TEXT);
$insert->bindParam(':first', $first, SQLITE3_TEXT);
$insert->bindParam(':last', $last, SQLITE3_TEXT);
$insert->execute();
?>
Here is the second file:
<?php
$user = SQLite3::escapeString($_GET['user']);
$db = new SQLite3("database.db");
$checkquery = $db->prepare('SELECT allowed FROM users WHERE username=:user');
$checkquery->bindParam(':user', $user, SQLITE3_TEXT);
$results = $checkquery->execute();
$row = $results->fetchArray(SQLITE3_ASSOC);
print(json_encode($row['allowed']));
?>
First, when you are done with a resource you should always close it. In theory it will be closed when it is garbage-collected, but you can't depend on PHP doing that right away. I've seen a few databases (and other kinds of libraries for that matter) get locked up because I didn't explicitly release resources.
$db->close();
unset($db);
Second, Sqlite3 gives you a busy timeout. I'm not sure what the default is, but if you're willing to wait a few seconds for the lock to clear when you execute queries, you can say so. The timeout is in milliseconds.
$db->busyTimeout(5000);
I was getting "database locked" all the time until I found out some features of sqlite3 must be set by using SQL special instructions (i.e. using PRAGMA keyword). For instance, what apparently solved my problem with "database locked" was to set journal_mode to 'wal' (it is defaulting to 'delete', as stated here: https://www.sqlite.org/wal.html (see Activating And Configuring WAL Mode)).
So basically what I had to do was creating a connection to the database and setting journal_mode with the SQL statement. Example:
<?php
$db = new SQLite3('/my/sqlite/file.sqlite3');
$db->busyTimeout(5000);
// WAL mode has better control over concurrency.
// Source: https://www.sqlite.org/wal.html
$db->exec('PRAGMA journal_mode = wal;');
?>
Hope that helps.
When I open a MySQL connection in PHP with just PHP's built-in MySQL functions, I do the following:
$link = mysql_connect($servername, $username, $password);
mysql_select_db($dbname);
//queries etcetera
mysql_close($link);
When I open a connection with PDO, it looks like this:
$link = new PDO("mysql:dbname=$dbname;host=$servername",$username,$password);
//prepare statements, perform queries
Do I have to explicitly close the connection like I do with mysql_connect() and mysql_close()? If not, how does PHP know when I'm done with my connection?
TIA.
Use $link = null to let PDO know it can close the connection.
PHP: PDO Connections & Connection Management
Upon successful connection to the database, an instance of the PDO class is returned to your script. The connection remains active for the lifetime of that PDO object. To close the connection, you need to destroy the object by ensuring that all remaining references to it are deleted--you do this by assigning NULL to the variable that holds the object. If you don't do this explicitly, PHP will automatically close the connection when your script ends.
PDO does not offer such a function on its own. Connections via PDO are indirectly managed via the PDO objects refcount in PHP.
But sometimes you want to close the connection anyway, regardless of the refcount. Either because you can not control it, need it for testing purposes or similar.
You can close the Mysql connection with PDO by running a SQL query. Every user that is able to connect to the Mysql server is able to KILL at least its own thread:
/*
* Close Mysql Connection (PDO)
*/
$pdo_mysql_close = function (PDO $connection) {
$query = 'SHOW PROCESSLIST -- ' . uniqid('pdo_mysql_close ', 1);
$list = $connection->query($query)->fetchAll(PDO::FETCH_ASSOC);
foreach ($list as $thread) {
if ($thread['Info'] === $query) {
return $connection->query('KILL ' . $thread['Id']);
}
}
return false;
};
$pdo_mysql_close($conn);
Related Mysql Documentation:
13.7.5.30. SHOW PROCESSLIST Syntax
13.7.6.4. KILL Syntax
Related Stackoverflow Questions:
PHP PDO close()? (Apr 2012)
When the PHP script finishes executing, all connections are closed. Also you don't have to explicitly close your connection with mysql_close().
You can also limit your connections to within local functions. That way the connection is closed as soon as the function is completed.
Well seeing as the $link for the PDO is assigned an object, PHP would set that as null as soon as the script runs so that it's no longer an object. Therefore you could just do:
$link = new PDO("mysql:dbname=$dbname;host=$servername",$username,$password);
//prepare statements, perform queries
$link = null;
http://uk3.php.net/pdo
From what i gather i could not see anyway to close it in the php manual, and examples of scripts i quickly looked at never closed the connection in anyway from what i could see.