Test mysql/PDO connection - php

The point of failure for my website is the database. I connect to it in a line included on all pages on the site that looks like this:
$GLOBALS['database'] = new PDO('mysql:mysql.host.address;dbname=db1', 'USER', 'PASSWORD');
If the database has too many connections open, I get a fatal error. I'd like to do this:
header('Location: http://www.website.org/sorry.php', true, 302);
Is there a test that will, instead of giving a "too many errors" message, let me do that 302? Do I need to use a timer that's one second less than the timeout on mysql?

try this?
try{
$GLOBALS['database'] = new PDO('mysql:mysql.host.address;dbname=db1', 'USER', 'PASSWORD',
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}catch(PDOException $ex){
header('Location: http://www.website.org/sorry.php', true, 302);
}

Related

PHP - Is this way I update and select from my database secure?

Recently, I switched to PDO and wanted to ask if is as safe as I do it or not?
(I filter the data before with much filter methods provided by php)
QUERY db:
include 'path_to_config_file_with_login_creds_for_db.php';
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
PDO::ATTR_PERSISTENT => false,
);
try {
$pdo = new PDO('mysql:host=' . $database_host . ';dbname=' . $database_name . ';charset=utf8mb4', $database_user, $database_pass, $options);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $exception) {
die("some error message");
}
try {
$statement = $pdo->prepare($sql);
$statement->execute($bindings);
$statement->closeCursor();
return $output;
} catch (PDOException $stmEx) {
die("again some error message");
}
UPDATE db:
include 'again_path_to_config_file_where_creds_to_db.php';
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
PDO::ATTR_PERSISTENT => false,
);
try {
$pdo = new PDO('mysql:host=' . $database_host . ';dbname=' . $database_name . ';charset=utf8mb4', $database_user, $database_pass, $options);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $exception) {
die("...");
}
try {
$statement = $pdo->prepare($sql);
$statement->execute($bindings);
$statement->closeCursor();
} catch (PDOException $stmEx) {
die("...");
}
Is this way safe or not?
It's all working fine but I want to know it its safe too
From the security point of view it should be safe as long as the query in $sql uses param binding properly. If the $sql variable is build like this then your code won't help you.
//DO NOT TRY THIS AT HOME
$sql = "SELECT * FROM `users` WHERE user='" . $_POST['user'] . "'";
But i can see several other issues with your code.
1) Your try ... catch blocks are useless. When you use PDO::ERRMODE_SILENT the PDO won't raise any exception. Only the $pdo->errorCode or $statement->errorCode properties will be set when error is encountered.
2) You are opening too many connections. I assume that you have the code you've shared in some function that you plan to call like queryDb($sql, $params); That means that every time you will call that function you will create new instance of PDO and open new connection. You might want to move the part that creates PDO instance into the db-config file then use that single instance everytime you are going to create new statement using $pdo->prepare().
3) The use of die. It's common practice to use die or exit when the query goes wrong in examples. But in actual application it would mean the user will see ugly empty page with single sentence saying something went wrong. It's better to throw an exception that will be handled higher in your app. That would let the application to display the page layout with menu and other things even if the requested action failed.
4) You do not set the value to $output variable in your first "Query DB" part of code. Although i'm not sure if you just left it out when copying or if you have it like this in your actual code.
In regards to SQL injection, as long as you parameterize all inputs and white list all dynamic SQL parts, you should be safe.
However, your code has another serious problem. You are silencing errors. PDO::ATTR_ERRMODE should be set to PDO::ERRMODE_EXCEPTION. But, that would leave your code even in a worse state, as you have die all over the place. Don't catch the exceptions unless you have extremely good reason to do so. Read this article https://phpdelusions.net/pdo#errors
Silencing or displaying errors to the user opens up new vectors for exploitation. That is why the best course of action is to leave them alone. In production system you should have the configuration set to never display errors. They will be securely logged on the server.

PDO Doesn't send a 500 code upon failure

My website sends an XMLHttpRequest to this PHP script:
<?php
if(isset($_POST))
{
require ('../../PDOConnect.php');
try
{
$insert = $pdo->prepare("INSERT INTO priorities
employeeID, WorkOrderNumber
VALUES (?,?)");
$insert->bindValue(1,$_POST['employeeID'],PDO::PARAM_INT);
$insert->bindValue(2,$_POST['WorkOrderNumber'],PDO::PARAM_INT);
$insert->execute();
echo "try";
}
catch(Exception $e)
{
echo "catch";
echo $e;
}
}
?>
At this point, the priorities table does not exist. I'm expecting the XMLHttpRequest's status to be 500 because the query obviously will always fail. PDO does log the error because PDOConnect contains
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING);
but I get a 200, not a 500. I'm new to PDO. When I was using MySQLi prepared statements, I would get a 500 back from failed PHP scripts, but PDO acts differently. I want the client to know that the query failed, rather than getting a 200 back and thinking that everything went okay. I get the same results with and without try and catch. Am I failing to understand how PDO works? Do I need to change a PDO setting?
Edit: I added echo "try"; and echo "catch";. The client's responseText is always "try", never "catch". It seems that the catch statement doesn't run. Why is that?
My PDOConnect.php file contains:
<?php
$options =
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING,
];
$pdo = new PDO('mysql:host=localhost;dbname=mydb;charset=utf8mb4','root','mypassword',$options);
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING);
?>
Make sure the PDO options are set correctly. It's importand to set the PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION option via the $option parameter of the PDO constructor. Don't set this option via setAttribute(), it's pointless.
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES $charset COLLATE $collate"
];
$pdo = new PDO($dsn, $username, $password, $options);
Then handle the Exception and send the 500 http error code:
try {
// do something
} catch(Exception $ex) {
header('500 Internal Server Error', true, 500);
echo $ex->getMessage();
}
You can also try this in your try...catch syntax to know what error you are getting in your PDO query.
<?php
try {
//pdo query
}
catch(PDOException $e) {
echo 'Exception -> ';
var_dump($e->getMessage());
}
Then note that 200 response means that your Ajax request succeeded. If you're getting a 500 response then check your configuration. The 500 Internal Server Error is a very general HTTP status code. It means something has gone wrong on the website and webserver is unable to specify what exactly, thus failing in fulfilling the request made by the client. This is not related to client and the fault is in the webpage/website requested that resides on server. This status code can be considered as a ‘catch-all’ server error of Web server.

Catch exception while mysql die - slim and prevent log to php_error log in that case

Hi I have the following code :
try {
$sth = $this->container->db->prepare("select x from table");
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_ASSOC);
return $result;
} catch (\PDOException $e) {
throw new ServerException("Could not get data");
} catch (\Exception $e) {
return false;
}
using slim 3 with wamp
the problem is when I point to the API(polling every 1 second) I got the following error:
Fatal error: Call to a member function prepare() on boolean in /
2 issues : it throws an error to the client
and it throws an error in php_error.log under wamp and the file becomes bigger
how can I prevent and catch those errors
PDO class:
public function getConnection($dsn, $username, $password) {
$conn = null;
try {
$conn = new PDO($dsn, $username, $password);
//Set common attributes
$conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
return $conn;
} catch (PDOException $e) {
return false;
//TODO: flag to disable errors?
throw $e;
}
catch(Exception $e) {
die();
//TODO: flag to disable errors?
throw $e;
}
}
Like many learners, you are taking this matter upside down
You should never actually catch an exception like this.
it throws an error to the client
Disable it for the whole site on the live server. There should be not a single PHP error message shown to the user, no matter if it's PHP exception or a filesystem error. Set display_errors to a negative value and forget this matter for all.
how can I prevent and catch those errors
Again, you should never do anything like this, bluntly catching every error and just dismissing it. It's like using the notorious # operator
it throws an error in php_error.log under wamp and the file becomes bigger
Ok, only this one makes sense. There are two possible solutions:
The best one: configure your mysql server properly so it wouldn't die under such a light load like 1 RPS.
Okay, what you actually want but I still don't recommend as it never pays to sweep the dirt under the rug: catch the exception, then verify if it's one you expect, then do something (i.e. try to reconnect after a short timeout), but re-throw the exception otherwise so you will have an idea when something else would go wrong. For this purpose you should add a condition in the try..catch block that should verify the error, handle it if it's one that you expect or just throw it again otherwise.
Of course, in order to catch a PDOException you have to enable it for PDO.
1) In Slim you should use the container (service factory) to build the PDO object. Example:
$container['db'] = function (Container $container) {
$settings = $container->get('settings');
$host = $settings['db']['host'];
$dbname = $settings['db']['database'];
$username = $settings['db']['username'];
$password = $settings['db']['password'];
$charset = $settings['db']['charset'];
$collate = $settings['db']['collate'];
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES $charset COLLATE $collate"
];
return new PDO($dsn, $username, $password, $options);
};
2) You must set the PDO options into the constructor to make it work. Example:
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];
$pdo = new PDO($dsn, $username, $password, $options);

How to get PHP and PDO working in Godaddy shared hosting?

I have a fatal error showing when I am trying to get MySQL to use a PDO instance in Godaddy shared hosting.
Code I tried to connect my database:
code 1
try{
$connect = new PDO('mysql:host=localhost;dbname=dbname;charset=utf8', 'user', 'password',
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
die('Error connecting to database');
}
When I used this code, it is printing 'Error connecting to database'
code 2
$dsn = 'mysql:host=localhost;dbname=dbname';
$user = 'user';
$password = 'password';
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
When I used this code it is printing an error:
'Connection failed: SQLSTATE[HY000] [1044] Access denied for user 'user'#'localhost' to database 'dbname"
Godaddy support is saying it is a string error that I have to review from my end and they are asking paid service to resolve it from their end. I found this both code running in my local server (xaamp).
First, make sure everything is correct in your config array, then add '\' this before PDO instance:
// Define Config Options
$config = [
'username' => 'YourUsername',
'password' => 'YourPassword',
'database' => 'YourDatabase'
];
// Make a function to easily access it
function connect($config)
{
try{
$conn = new \PDO('mysql:host=localhost;dbname=' .$config['database'], $config['username'], $config['password']);
$conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
return $conn;
}
catch(Exception $e){
return false;
}
}
In shared hosting you normally find that the mysql server is not localhost, you normally find that your provider will place the mysql server on a separate machine.
Login in to you control panel with godaddy and look at the settings, you'll probably have to create a database first.

How I check PDO connected to appropriete database

I use this code for check connection to the database(MYSQL).If the database name not available then also it show connect successfully.
if(isset($_REQUEST['submit']))
{
echo $name = $_REQUEST['name'];
echo $pwd = $_REQUEST['password'];
$servername = "localhost";
$username = "root";
$password = "";
try
{
$conn = new PDO("mysql:host = $servername;dbname = pdo",$username,$password);
//echo "Connected successfully";
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "connect successfully";
}
catch(PDOException $e)
{
echo "Connection failed: " . $e->getMessage();
}
}
TL;DR
Because your code is using try-catch blocks you can be sure that as long as no exceptions are thrown the connection was successfully established. Otherwise check the error code stored inside the exception to resolve the type of error.
More detailed
Your code makes use of exceptions, so if an error occurred while a connection was attempted established an exception would be thrown. As far as I know the PDO object throws exceptions by default while it is constructed and falls back to silent mode when to instance is created. So you are assured you will be warned if anything bad happens during construction.
Update 1
How to check the database name is available or not in to the database using PDO?
As said you can utilize exceptions. But instead of echoing the exception message you can inspect the returned error code using the PDOException method getCode(). Using php version 5.6.8 I will get the code 1049. You can then check using the following:
try {
$pdo = new PDO($dsn, $username, $passowrd, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
]);
}catch(PDOException $exception) {
if($exception->getCode() == 1049) {
echo 'Database does not exist!';
}
// Continue error handling...
}
Update 2: Alternative
Using the same PHP version as above you can avoid selecting a database in the DSN. With this you can fetch a list of accessible databases for the used MYSQL user. Using this list you can check the existence of one or more databases at the same time and avoid the overhead of an exception halting execution of your script.
/*
* I assume you are on localhost.
*/
$pdo = new PDO('mysql:host=127.0.0.1', $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
]);
$databases = $pdo->query('SHOW DATABASES'); // Does not require a prepared statement since it takes no input.
/*
* The following can be done more elegant/efficient.
*/
$exists = false; // Equals TRUE if the database exists.
$check = 'test'; // Enter the database to check for.
foreach($databases->fetchAll(PDO::FETCH_ASSOC) as list($database)) {
if($database == $check) {
$exists = true;
break;
}
}
Bonus
You are setting the error mode after the PDO instance has been constructed. This can also be done with the fourth parameter of PDO's constructer. I think this leads to more readable code.
I would also recommend setting the configuration PDO::ATTR_EMULATE_PREPARES to false. This ensure prepared statements are always used. The documentation can be found here.
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
]);
Happy coding!

Categories