handling double username in mysql and php - php

I'm writing my own implementation of an API. One of the resources of this API is /user, I can POST a JSON string to this, parse it and send it to a UserService which has an addUser method. Now obviously I can't allow two users to have the same username. This is what I have to so far.
protected function handlePost() {
$user = json_decode($this->getRequest()->getRequestData(), true);
try {
$createdUserId = $this->userService->addUser(
$user['username'],
$user['password'],
$user['typeId'],
$user['companyId']
);
} catch (PDOException $e) {
$this->getResponse()->setStatus(102);
}
if ($createdUserId)
$this->getResponse()->setStatus(101);
$this->getResponse()->sendResponse();
}
This function is called after the HTTP request has been parsed. As you can see, I get the $user object in an associative array. I then use these values as parameters to the $this->userService->addUser method.
This is the addUser() method:
public function addUser($username, $password, $type, $companyId) {
$sth = $this->dbh->prepare('INSERT INTO app_user
(username, password, typeId, companyId)
VALUES (?, ?, ?, ?)');
$userAdded = $sth->execute(array($username, md5($password), $type, $companyId));
return ($userAdded)
? $this->dbh->lastInsertId()
: null;
}
Now if the $sth->execute fails for some reason, I return null (and neither status code 101 or 102 will be returned, I'm aware of this). But if a username already exists PDO throws an exception, which I catch in my handlePost() method above.
My problem with this is of course that a username which has already been taken is not exceptional and should not be handled this way but I don't really know how I should handle it?
It must remain possible for me to be able to distinguish between a unique constraint being triggered and some other (maybe concurrency issue) being triggered so I can send the appropriate status code back to the consumer of the API.
An obvious solution would be to check if the username exists in a a separate query but for obvious reasons I would prefer to keep the calls to the database limited.
How can I solve this elegantly? If I do have to use exceptions, is there a list of specific PDO exceptions so that I don't have to use the generic PDOException?

Are you concerned enough with performance (i.e. minimizing queries against the database) that you wouldn't just check the existence of the user name in the database before trying to do an insert? You might find this easier logic to follow than trying to catch the Exception and figure out if there really is an exception or not based on the number of rows effected with the last query or similar.
I would also add that if you want to make it not an exception you could add ON DUPLICATE KEY logic to your insert.

PDO should not send an exception for an integrity constraint violation if your not using the ERRMODE_EXCEPTION in your PDO constructor.
In that case, you must call the method PDOStatement::errorCode() or PDOStatement::errorInfo()
to get the details of the error and see if it's an integrity constraint violation or a real problem.

Related

Handling PDO and Statement Exceptions

We have been going through some old code of ours and we have found some code that looks something like:
try
{
$stmt = $db->prepare($query);
$stmt->bindvalue(1, $id, PDO:ARAM_INT);
$stmt->execute();
$row = $stmt->fetchColumn();
}
catch(PDOException $e)
{
echo "There was an issue with query: ";
print_r($db->errorInfo());
}
Which at first glance we thought looked fine (Even many answers on Stack Exchange give this as example code). Then we looked at the PHP documentation for the errorInfo function and it states that:
PDO::errorInfo() only retrieves error information for operations performed directly on
the database handle. If you create a PDOStatement object through
PDO:repare() or PDO::query() and invoke an error on the statement
handle, PDO::errorInfo() will not reflect the error from the statement
handle
Which, if we understand it correctly, means that if anything goes wrong in any of the statement operations we do, we will not actually print out the error code we are expecting after "There was an issue with the query: ". Is this correct?
In light of this, we started looking for the proper way to do this, we started by looking at the PDOException class documentation which suggests that we might do something like:
try
{
$stmt = $db->prepare($query);
$stmt->bindvalue(1, $id, PDO:ARAM_INT);
$stmt->execute();
$row = $stmt->fetchColumn();
}
catch(PDOException $e)
{
echo "There was an issue with query: ";
print_r($e->errorInfo());
}
My questions are:
Is the above way the proper way of doing this? If not, what IS the proper way of doing it?
Is there any more useful information avaliable by using $db->errorInfo() and $db->errorCode ( or $stmt->errorInfo and $stmt->errorCode ) beyond what you can see from PDOException?
If there IS anything more detailed available-and-useful from those detailed calls, then is there a way to differentiate, by examining the PDOException, whether it was thrown by PDO or by PDOStatement?
The exception may be thrown by either $db->prepare or any of the $stmt operations. You do not know whence the error originated, so you should not guess. The exception itself contains all the information about what went wrong, so yes, consulting it and only it is the only sensible thing to do.
Moreover, it's usually nonsense to try..catch directly around the database call (unless you have a clear plan about something you want to do if this particular database operation fails). In your example, you're merely outputting the error and are continuing as if nothing happened. That's not sane error handling. Exceptions explicitly exist to abort and jump ship in case of a severe error, which means the part of your code which should actually be catching the exception should live several layers up and not have access to $db or $stmt at all (because it's in a different scope). Perhaps you should't be catching the exception at all and have it terminate your entire script (again, unless you expected an error to occur and have a clear plan how to handle it and how to recover your application into a known state). So looking only at the information in the exception itself is, again, the only sensible thing to do.
If there IS anything more detailed available-and-useful from those detailed calls, then is there a way to differentiate, by examining the PDOException, whether it was thrown by PDO or by PDOStatement?
This is only useful if, again, you have any sort of plan for recovery and that plan differs depending on where the error occurred. First of all, I doubt that, but if that's indeed the case, then you'd do something like this:
try {
$stmt = $db->prepare($query);
} catch (PDOException $e) {
// do something to save the day
}
try {
$stmt->bindValue(...)
..
} catch (PDOException $e) {
// save the day another way
}
In other words, you isolate the try..catch statements to smaller parts of your code that you want to distinguish. But, really... if $db->prepare failed, what are you going to do? You can't continue with the rest of the code either way. And what are you going to do differently than if a $stmt method failed? As one atomic unit, you were unable to query the database, period.
The PDOException::$code will give you the more detailed SQLState error code, which may tell you something useful (e.g. unique constraint violation), which is useful information to work with on occasion. But when inspecting that it's pretty irrelevant which specific line threw the error.

Is it best practice to always check the return value of PDOStatement::execute?

I have a Permission class with a method similar to the following.
public function AddComponentToAccount($component_id,$account_id)
{
$sql = "INSERT INTO component_permissions
(account_id,component_id)
VALUES
(:account_id,:component_id)";
$q = $this->db->prepare($sql);
$q->bindValue(':acount_id',$account_id);
$q->bindValue(':component_name',$component_id);
$q->execute();
}
My question is - should the final line really be return $q->execute();? Of the two following, which is better? Or is this subjective?
if(!$Permission->AddComponentToAccount($component_id,$account_id)){
...
}
-
try {
$Permission->AddComponentToAccount($component_id,$account_id)
} catch(Exception $e) {
HandleError($e);
}
I already know that the variables being passed into AddComponentToAccount are good. Exceptions could be a composite PK violation, or the fact that the DB is down.
That depends on the PDO Error Handling method.
If you are using PDO::ERRMODE_EXCEPTION, then you need a try...catch block
If you are using PDO::ERRMODE_SILENT or PDO::ERRMODE_WARNING you only need to manage error code(s)
Now considering where to manage the error, I prefer to let exceptions bubble up in the caller code, in this way you can manage your behavior based on the caller (that is what exception are made for).
Addressing your question, if you are using PDO::ERRMODE_EXCEPTION you don't need to manage both the return code and the exception itself.

Best way to build a database of php errors using mysql?

I'm building a newsletter CMS and I want to loog any errors to a database with information like timestamp, error, userID and function info. What's the best way to do this?
I'm thinking I should build a class that handles the errors and inputs them into a MYsql table using PDO.
pseudo code:
class sbmtErr
{
private $errStrng;
protected function sndErr($err, $usrData, $mthd){
$sndErrPDO = new myPDO;
$this->errStrng = "INSERT INTO errTbl (error, userID, method) VALUES ('".$err."', ".usrData['usrID'].", '".$mthd."')";
$sndErrPDO->sqlQry($errStrng);
}
}
My problem here is I don't know how to isolate the method that threw the error.
Is there a better way to do this?
Thanks.
Extend the exception class. CMSErrorException , when thrown (i.e. On construct) use reflection to find out things like function, line number, etc. how you find the user's id depends on how you keep it.
Then, regardless of what you do when you catch it, you call a method (again from the construct) which logs it into the database.
Careful not to throw these custom exceptions inside of the exception code, as it might cause an infinite loop in case of a database error.

Detect mysql update/insertion failure due to violated unique constraint

This is kind of similar to this question:
PHP MySQL INSERT fails due to unique constraint
but I have a different twist. Let's say I have a table with only one column. The column's name is "title" and it has a unique constraint placed on it.
First I insert a row where title = "something". The next time I try to insert "something" it will fail due to a unique key constraint (which is good). What I'd like to do is allow it to fail, and check the error code provided by mysql to ensure it failed due to a unique key constraint. (i.e. let the database handle the uniqueness, and I just handle the error code and tell the user that title already exists when the result comes back).
Is there a way to do this?
Now that it's the year 2015, there are very few reasons not to be using PHP's PDO implementation.
The proper, modern, "OO" method for detecting and handling an insertion failure due to a key constraint violation is as follows:
try {
//PDO query execution goes here.
}
catch (\PDOException $e) {
if ($e->errorInfo[1] == 1062) {
//The INSERT query failed due to a key constraint violation.
}
}
The PDOException object has a lot more to say about the specific nature of the error, too (more detail than one could possibly ever want or need, seemingly).
http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
http://php.net/manual/en/function.mysql-errno.php
I've had to do this in the past, and it's not fun:
if( mysql_errno() == 1062) {
// Duplicate key
} else {
// ZOMGFAILURE
}
A note on programming style (Credits to jensgram from this answer)
You should always seek to avoid the use of magic numbers. Instead, you could assign the known error code (1062) to a constant (e.g. MYSQL_CODE_DUPLICATE_KEY). This will make your code easier to maintain as the condition in the if statement is still readable in a few months when the meaning of 1062 has faded from memory :)
I believe the error code for duplicate keys is 1586. If you were to attempt to execute a query and then, on failure, check the error code using mysql_errno()/mysqli::errno() and compare it to 1586, that should do it. If it's not 1586, check what it actually is by echoing the error code after your query.
Why not just do a select first to see if the entry already exists. Or suppress an error altogether by using INSERT ON DUPLCATE KEY UPDATE, or even use the mysql IGNORE keyword. Why purposely cause an error?
Topic is of interest for fellow PHP/Mysql users so let me outline a solution.
Please note
There is no magical portable way to do it
situation is not unique to PHP, if you want to detect DB2 unique key constraint violation with openJPA - you have to restore to similar kind of handling
Suppose you have a form - where you have a field "Name"
1) In the DB table
Add a unique constraint like -
alter table wb_org add constraint uniq_name unique(name);
2 ) The form handler script
The form handler script should pass the data to DB layer and if there are any errors, the DB layer would signal it as an DBException (An exception defined by us). we wrap the code sending data to DB layer in a try-catch block (only relevant code is shown)
try{
....
$organizationDao = new \com\indigloo\wb\dao\Organization();
$orgId = $organizationDao->create($loginId,$fvalues["name"]) ;
....
} catch(UIException $ex) {
....
// do UI exception handling
} catch(DBException $ex) {
$errors = array();
$code = $ex->getCode();
$message = $ex->getMessage();
// look for code 23000, our constraint name and keyword duplicate
// in error message thrown by the DB layer
// Util::icontains is just case-insensitive stripos wrapper
if( ($code == 23000)
&& Util::icontains($message,"duplicate")
&& Util::icontains($message,"uniq_name")) {
$errors = array("This name already exists!");
} else {
// Not sure? show generic error
$errors = array(" Error: doing database operation!") ;
}
// log errors
Logger::getInstance()->error($ex->getMessage());
Logger::getInstance()->backtrace($ex->getTrace());
// store data in session to be shown on form page
$gWeb->store(Constants::STICKY_MAP, $fvalues);
$gWeb->store(Constants::FORM_ERRORS,$errors);
// go back to form
$fwd = base64_decode($fUrl);
header("Location: " . $fwd);
exit(1);
}catch(\Exception $ex) {
// do generic error handling
}
Please note that you have to find the ex->getCode() for your situation. Like in above, the PDO layer is actually throwing back the SQLSTATE 23000 as ex->code ( where the actual mysql error code is 1062). The code can vary from DB to DB also. Same way ex->message can also vary. It would be better to wrap this check in one place and fiddle using a configuration file.
3) inside DB layer (using PDO)
static function create($loginId, $name) {
$dbh = NULL ;
try {
$dbh = PDOWrapper::getHandle();
//Tx start
$dbh->beginTransaction();
...
// do DB operations
//Tx end
$dbh->commit();
$dbh = null;
} catch(\Exception $ex) {
$dbh->rollBack();
$dbh = null;
throw new DBException($ex->getMessage(),$ex->getCode());
}
4) Back on the form (after hitting form Handler => DB Layer => Form Handler error handler => Form)
Extract error messages set in session and display them on the form.
5) DBException class
<?php
namespace com\indigloo\exception {
class DBException extends \Exception {
public function __construct($message,$code=0, \Exception $previous = null) {
// PDO exception etc. can return strange string codes
// Exception expects an integer error code.
settype($code,"integer");
parent::__construct($message,$code,$previous);
}
}
}
?>
6) icontains utility method
static function icontains($haystack, $needle) {
return stripos($haystack, $needle) !== false;
}
Can we do this without exceptions and PDO?
7) without PDO and using only mysqli
Get error code and error message from mysqli and throw DBException from DB layer
Handler the DBException same way.
8) Can we do this w/o using exceptions?
I am writing this without any experience of actually doing it in live code. So please let me know if you do not agree. Also, please share if you have a better scheme. if you just want a catch-it-all generic sort of handler then yes.
inside the DB layer: raise errors using trigger_error instead of throwing exceptions. inside trigger_error method - use some MAGIC_STRING + DB_CODE
define a custom error handler for form handler page
inside your custom error_handler for form handler : look for MAGIC_STRING + code
if you get MAGIC_STRING + code then
set appropriate message in session
forward to form page
display a custom message set in session
The problem I find with trigger_error and error_handlers is that
you cannot trap them in the flow of execution like you can do with exceptions. However this is not a problem in our case because our error_handler for page just needs to redirect to form page.
I do not know a way to raise specific error codes (what code I want) with trigger_error method. If only it were possible to raise an error with code X and our message Y. So far as I know you cannot do that. That is why we are restoring to parsing every error_message that our error_handler receives.
I do not have much experience working with error codes (I have been raised on exceptions) - so maybe someone else can enlighten us.
The code samples are from my public github repo https://github.com/rjha/website - code that I am writing for create a website builder to launch thousands of sites from same DB. The code above is used to check unique name for a website.
From PHP Documentation on the function mysql_errno:
Returns the error number from the last MySQL function,
or 0 (zero) if no error occurred.
Also, from MySQL Documentation on Constraint Violation Errors, error code 893 corresponds to:
Constraint violation e.g. duplicate value in unique index
So, we can then write something like this to do the work:
if (!$result) {
$error_code = mysql_errno();
if ($error_code == 893) {
// Duplicate Key
} else {
// Some other error.
}
}
If you know some SQL, try this solution (tested)
$username = "John";
$stmt = $pdo->prepare("
INSERT INTO users (
username
) SELECT * FROM (
SELECT :username
) AS compare
WHERE NOT EXISTS (
SELECT username
FROM users
WHERE username = :username
) LIMIT 1;
");
$stmt->bindParam(":username", $username);
if ($stmt->execute()) {
if ($stmt->rowCount() == 0) {
echo "Dublicate Username, ".$username." already exists.";
} else {
echo $username." not in use yet.";
}
}

when do I write my own exception class?

I have been wondering since I stepped into the murky waters of OOP and have written a couple or so of distributed libraries when it is necessary to write my own extension of the exception class.
So far I simply use the built in exception class and it seems to serve me well. Is it necessary, and if so when is it ok, for me to write an exception subclass.
You should extend the Exception class with your own Exception types when you need to differentiate between different types of errors. Throwing an Exception just means something went wrong. You have no idea what went wrong though. Should you abort everything? Is this an expected error? Throwing a UserIsNotAllowedToDoThisException instead means something much more specific. The importance is to differentiate what code can handle what kind of error:
try {
new Foo($bar);
} catch (UserIsNotAllowedToDoThisException $e) {
echo "Sorry, you're not allowed to do this.";
}
This code handles the simple case when something is not allowed. If Foo would throw some other exception, like TheDatabaseJustCrashedAndIsBurningException, you don't want to know about this here, you want some global error handler to handle it. By differentiating what went wrong, it allows you to handle problems appropriately.
OK, here a little more complete example:
First, if you use proper OOP, you need Exceptions to fail object constructions. Without being able to fail object constructions, you're ignoring a large part of OOP: type safety and therefore data integrity. See for example:
class User {
private $name = null;
private $db = null;
public function __construct($name, PDO $db) {
if (strlen($name) < 3) {
throw new InvalidArgumentException('Username too short');
}
$this->name = $name;
$this->db = $db;
$this->db->save($this->name); // very fictional DB call, mind you
}
}
In this example, we see a lot of things:
My User objects have to have a name. Failing to pass a $name argument to the constructor will make PHP fail the whole program.
The username needs to be at least 3 characters long. If it is not, the object cannot be constructed (because an Exception is thrown).
My User objects have to have a valid and working database connection.
Failing to pass the $db argument will make PHP fail the whole program.
Failing to pass a valid PDO instance will make PHP fail the whole program.
I can't pass just anything as the second argument, it needs to be a valid PDO object.
This means if the construction of a PDO instance succeeded, I have a valid database connection. I do not need to worry about or check the validity of my database connection henceforth. That's the same reason I'm constructing a User object; if the construction succeeds, I have a valid user (valid meaning his name is at least 3 characters long). I do not need to check this again. Ever. I only need to type hint for User objects, PHP takes care of the rest.
So, you see the power that OOP + Exceptions gives you. If you have an instance of an object of a certain type, you can be 100% assured that its data is valid. That's a huge step up from passing data arrays around in any halfway complex application.
Now, the above __construct may fail due to two problems: The username being too short, or the database is for whatever reason not working. The PDO object is valid, so the connection was working at the time the object was constructed, but maybe it's gone down in the meantime. In that case, the call to $db->save will throw its own PDOException or a subtype thereof.
try {
$user = new User($_POST['username'], $db);
} catch (InvalidArgumentException $e) {
echo $e->getMessage();
}
So I'd use the above code to construct a User object. I do not check beforehand whether the username is at least 3 characters long, because this would violate the DRY principle. Instead, I'll just let the constructor worry about it. If the construction fails with an InvalidArgumentException, I know the username was incorrect, so I'll let the user know about that.
What if the database is down though? Then I cannot continue to do anything in my current app. In that case I want to halt my application completely, displaying an HTTP 500 Internal Server Error page. Here's one way to do it:
try {
$user = new User($_POST['username'], $db);
} catch (InvalidArgumentException $e) {
echo $e->getMessage();
} catch (PDOException $e) {
abortEverythingAndShowError500();
}
But this is a bad way. The database may fail at any time anywhere in the application. I do not want to do this check at every point I'm passing a database connection to anything. What I'll do instead is I let the exception bubble up. In fact, it has already bubbled up. The exception was not thrown by new User, it was thrown in a nested function call to $db->save. The Exception has already traveled up at least two layers. So I'll just let it travel up even further, because I have set up my global error handler to deal with PDOExceptions (it's logging the error and displays a nice error page). I do not want to worry about this particular error here. So, here it comes:
Using different types of Exceptions allows me to ignore certain types of errors at certain points in my code and let other parts of my code handle them. If I have an object of a certain type, I do not ever have to question or check or worry about its validity. If it wasn't valid, I wouldn't have an instance of it in the first place. And, if it ever fails to be valid (like a suddenly failing database connection), the object can signal by itself that an error occurred. All I need to do is catch the Exception at the right point (which can be very high up), I do not need to check whether something succeeded or not at every single point in my program. The upshot is less, more robust, better structured code. In this very simple example, I'm only using a generic InvalidArgumentException. In somewhat more complex code with objects that accept many arguments, you'd probably want to differentiate between different types of invalid arguments. Hence you'd make your own Exception subclasses.
Try to replicate this by using only one type of Exception. Try to replicate this using only function calls and return false. You need a lot more code to do so every time you need to make that check. Writing custom exceptions and custom objects is a little more code and apparent complexity upfront, but it saves you a ton of code later and makes things much simpler in the long run. Because anything that shouldn't be (like a user with a too short username) is guaranteed to cause an error of some sort. You don't need to check every time. On the contrary, you only need to worry about at which layer you want to contain the error, not whether you'll find it at all.
And it's really no effort to "write your own Exceptions":
class UserStoppedLovingUsException extends Exception { }
There, you have created your own Exception subclass. You can now throw and catch it at the appropriate points in your code. You don't need to do any more than that. In fact, you have now a formal declaration of the types of things that may go wrong in your app. Doesn't that beat a lot of informal documentation and ifs and elses and return falses?
The built in exception is good enough for almost every case. The only scenario that I could think of where you need another one is when there are more than one exception that can be thrown in a try and you want to do different things depending of which one is thrown. You have to distinguish two exceptions. therefore you need another one.
Only write it when you need it, e.g. to signal an own exception, for example if you code a library and no exception of the existing ones speaks the same.
See
Core PHP Exceptions
Core PHP SPL Exceptions
There are a lot of exceptions already build-in in PHP so for the normal program flow things should be covered exception-wise.
If you're developing a more complex system, like a parser, lexer plus compiler and everything is accessed via one routine/faced for it's API, the parser might want to throw a parser exception, the lexer a lexer exception and the compiler a compiler exception.
It can be useful to be able to differentiate. But I normally stick with the build in exceptions, it's easy to refactor later anyway in case it needs more differentiation.
And since there are namespaces nowadays, this is really freaking easy if you stick to the firsthand Exception class from the beginning ;)
IMHO:
Simply if you enter your own domain.
That is usually indicated when you need additional data to provide in your exception.
So actually you then also have to do you own class to add the additional class members.

Categories