Is there such a thing like an "executed" flag for PDOStatement (PDOStatement) to see if the statement has been executed (by calling PDOStatement::execute())? Or am I forced to just set my own flag?
Judging by the documentation, there doesn't seem to be a flag (the only documented property is $queryString) - but I thought I'ld still ask before doing it manually. Mainly to distinguish prepared from already executed statements.
Once a statement is prepared, you can execute it multiple times, so maybe the builders didn't think a flag like that would be useful, and personally I'm a bit curious about your use case too.
But it is possible: Using PDOStatement::errorCode, you can get the error code of the last statement. This function will return an exmpty string when the statement is not executed yet, and will be filled with an error code, (or 00000 for no error), after the statement is executed.
No there is not. You can reuse a PDOStatement, which is the use case supported with PDO:prepare.
Related
Under certain circumstances, the built-in function in PHP called mysqli_query returns null. Such behaviour is not foreseen by the function's documentation that explains how to use it, so I tried to dive in PHP's source code itself, posted on GitHub, to see if I can figure out why sometimes mysqli_query returns null.
The queries themselves doesn't seem to be the problem: I tested the relevant SQL queries in two different ways:
Executing them manually in the MySQL Server. They work correctly.
Within a script that I created with the single purpose of testing the queries through mysqli_query(). They work under this test, and the function returns true.
However, under certain conditions, those same queries return null. The mysqli link object exists when mysqli_query function starts running, when this "returning null failure" happens.
So, looking in the PHP's GitHub repository, i found the file called mysqli_nonapi.c and, in line 556 within this file, what seems to be the built-in mysqli_query definition. Looking at the code within, it looks like it performs a basic check and, if it fails, it returns null. Here are the first lines linked above:
/* {{{ proto mixed mysqli_query(object link, string query [,int resultmode]) */
PHP_FUNCTION(mysqli_query){
MY_MYSQL *mysql;
zval *mysql_link;
MYSQLI_RESOURCE *mysqli_resource;
MYSQL_RES *result = NULL;
char *query = NULL;
size_t query_len;
zend_long resultmode = MYSQLI_STORE_RESULT;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|l", &mysql_link, mysqli_link_class_entry, &query, &query_len, &resultmode) == FAILURE) {
return;
}
// [...]
}
Even though I have used sometimes C code, I just know a little about C. I am aware that it uses pointers and I guess those parameters which name start with * are pointers. Anyways, I am not sure on how to interpretate this piece of code, or figuring out how it's internal flow affects PHP execution.
Long story short: I can assume somehow, the initial check shown above within the function failed for some reason. But, to find out why, I need to understand that piece of code first.
I am afraid I cannot isolate the issue to trigger the error outside production environment, which would be very useful for exhaustive testing. So, what options do I have left? Is there something I can do to debug that internal piece of code, or otherwise, figuring out why it might be failing within?
I made the tests in both PHP5 and PHP7; it fails the same way in both of them.
This is called undefined behaviour in PHP. Most instances of it have been eradicated in PHP 8, but prior to that version when you passed a wrong parameter to a built-in function, that function would usually throw a warning and return null (or false).
There were a lot of circumstances when no warning was produced at all! This behaviour was not documented on each page as this would be a mess and by definition "undefined behaviour" has no defined behaviour.
This means that code like the following would throw no warning and simply return null:
// V - string passed instead of a numerical value
var_dump(mysqli_query($mysqli, 'SELECT 1', 'foo'));
PHP was very forgiving with parameter types and when you passed the wrong type, it tried to convert it into the proper type, but when this was not possible then PHP had no defined behaviour of what should happen. Thankfully, this has been fixed in 99% of cases in PHP 8.0.
TLDR: Does anyone know of specific cases, besides the one shown below, where PDO::exec(), PDO::query(), PDO::prepare(), or PDOStatement::execute() can return false without an exception being thrown, despite PDO::ATTR_ERRMODE being set to PDO::ERRMODE_EXCEPTION?
I'm trying to decide if I want to add a check for false to every database query I write going forward, or if that is redundant.
Edit: I currently use MySQL exclusively, but if portability is a factor, that might be enough to base the decision on. I use PDO::ATTR_EMULATE_PREPARES => FALSE if that matters.
This is the specific case I mentioned. If you prepare a statement with 0 or more placeholders (of either type) and then supply an array of arguments to PDOStatement::execute() with more elements than there are placeholders, false is returned without an exception being thrown. Note that the execution succeeds (and only the extra binding fails) if PDOStatement::bindValue() is used instead. Using fewer parameters than placeholders does throw an exception, whether the parameters were supplied to the execute function via an array or bound using PDOStatement::bindValue()/PDOStatement::bindParam().
// Execute returns false, no exception thrown
$so = $rh->pdo->prepare("SELECT * FROM config");
if($so->execute(['Test']) === FALSE) echo '1. False returned <br />';
// Execute does not return false, no exception thrown
$so = $rh->pdo->prepare("SELECT * FROM config");
if($so->bindValue(1, 'Test') === FALSE) echo '2. Binding failed <br />';
if($so->execute() === FALSE) echo '2. False not returned <br />';
// Execute returns false, no exception thrown
$so = $rh->pdo->prepare("SELECT * FROM config WHERE webmaster_name = ?");
if($so->execute(['Test', 'Wee']) === FALSE) echo '3. False returned <br />';
// Execute does not return false, no exception thrown
$so = $rh->pdo->prepare("SELECT * FROM config WHERE webmaster_name = ?");
$so->bindValue(1, 'Test');
if($so->bindValue(2, 'Wee') === FALSE) echo '4. Binding failed <br />';
if($so->execute() === FALSE) echo '4. False not returned <br />';
Outputs:
1. False returned
2. Binding failed
3. False returned
4. Binding failed
On a select statement, it isn't particularly dangerous in this case to rely on exceptions, as an error would occur anyway if you tried to call a fetch method on FALSE instead of a PDOStatement object. But there are queries like INSERTS or UPDATES that could silently fail on you if you don't do the false check.
I have been learning PDO and I am trying to decide on general practice for error handling going forward.
I definitely prefer exceptions, as I already have a good site wide handler that can be configured for different scenarios. And it seems using exceptions will mean less typing, since you don't have to check the returns of many PDO functions explicitly.
OR DO YOU? (cue dramatic music)
When I was reading up, I came across more than one mention of PDO functions (not the fetching variety) returning false without an exception being thrown.
My question is whether or not it is considered best practice to also check the return of those functions, or if most people consider that overkill.
I have seen a lot of conflicting statements on SO. I have seen numerous statements on one side: "PDO exceptions are reliable"; "PDO exceptions will always be thrown when FALSE would have been returned" (upvoted by people saying "I think is true").
These are some comments that are leading me to wonder, though I have yet to see a specific example besides the one I mentioned.
From Can PDO methods fail and not throw PDOException?:
I could not seem to replicate this scenario from a few test cases (I have emulation mode off).
"(Ryan Vincent) when emulates is false and ... binding types are incorrect. It may not throw an exception sometimes."
This one seems to have been disproved? I'm not sure how to test this.
"(Xorifelse) Now for committing to fail, I believe there is 1 scenario that would cause it to return false without throwing an exception and that is when the connection to the server drops after connecting to the database and before calling PDO::commit, quite good to know if you have a remote database server. So to answer your question, yes it can fail without throwing an exception, but its timing has to be very specific even more so if you have a local database."
From will a false returned PDO execute() the same as the exception it thrown?:
This is the only specific scenario I have come across that I have been able to duplicate (see above).
"(Niksac) I have seen execute() returning false without throwing an exception which is kind of unexpected / bad behaviour in my opinion. This means that we basically have to do both - error and exception handling in parallel. In my case: if I prepared an insert query without any parameters and then executed with a parameter. Execute will not throw an exception but return false."
From Should I check the return value of an execute operation in pdo php:
"(castis) $stmt->execute() can absolutely return false without throwing an exception."
I think I found at least one other non-specific mention of it being possible (false returned, no exception), though I can't track them down again.
Looking through PDO tutorials online, most of them don't check the returns whenever exception mode is used. But I did come across a couple people recommending it.
The case I described is not something I am likely to screw up in everyday use. Or if I do screw it up, I should find out immediately. And if I ever dynamically built the number of placeholders or parameters in the query, I would know to make sure the count matches and/or check for false in this one case.
I just don't want to check the return of every use of execute, query, etc. if it isn't really necessary. If the example I mentioned is the only known case, I would feel comfortable leaving the false check out of most queries, which would allow me to do more method chaining:
$user_info = $rh->pdo->query("SELECT * FROM users WHERE user_id = 1")->fetch();
// vs
$so = $rh->pdo->query("SELECT * FROM users WHERE user_id = 1");
if($so === FALSE) // Throw an exception
$user_info = $so->fetch();
I guess what I'm looking for is some reassurance from more experienced developers that it's okay to bypass this check as I'm seeing people do. Either that, or people telling me how they have been burned by bypassing that check.
There are definitely different gotchas depending on which database you are using. If portability is a concern, I'd not rely on some of what might be MySQL idiosyncrasies that you seem to be finding, above.
For example, there are these:
PHP PDO Postgres versus Sqlite column type for count(*)
PHP Postgres PDO driver does not support prepared statement?
I do not have control over the code I'm executing. This is a third party function, but not user-entered. These are things that are versioned so it is impractical that I poke there and change all die()'s into something more sane. Because a new version is coming from time to time and then I could paradoxically make the code even more insecure by trying mess with it poor error handling.
so let's say we have a function:
fuction myfunc() {
// lot's of complicated code
if (!is_file('myfile.txt') exit('file not found');
// and so on
}
What I'm trying to do is to somewhat run that piece of code and return to my main thread and then act accordingly with that error.
I've tried die() or eval() but this returns the whole script.
Bummer ?
A Hail Mary approach is to use runkit's runkit_function_redefine or function_override to redefine the functions die and exit to throw an Exception instead.
A potential problem is that the 3rd party can catch those exceptions and might not deal with them correctly. It's also very likely that you can't properly deal with the exception either.
You can use register_shutdown_function to run code after exit has been called. You are somewhat limited in what you can do at this point as some services have already been shut down (such as autoloading). I think you can still output content, not sure about sessions and other headers.
Another approach would be to run the code in a seperate php process (or http request), for instance by calling php through exec.
A more solid approach can be to add predicitions to your own code, ensuring the bad states are never reached when calling the 3rd party code. It is possible that not all preconditions can be met.
Ideally only code that is an entry point (like a router script) may exit. Using exit anywhere else is just shoddy programming really.
If you have not read Halcyon's answer, you should have a look at it first.
Since you mention eval(), I assume you have the code as a string. I will refer to both die() and exit() by just the latter, but things should be relevant for both.
You can try and replace occurrences of die() and exit() with something, and then eval. It's simple but that can be very messy.
One thing to look out for, IF you decide to do this, is that you may end up replacing occurrences which are not really 'code'. For example, echo "Let him exit()";.
Also, when you consider possible equivalent syntax, like exit (); , exit; or exit(1);, it gets much more unpleasant. You'll have to handle those with a regex.
But if you can safely assume that
those two signatures (die() and exit()) are the only ones you need to worry about; and
that strings (or other content) are not going to contain those 'phrases'
then you can use this approach.
Here is the edited script without errors. And the 2 fixes applied to it. To those who helped in part, thank you. To mentions that the code is unclear or messy is inconsequential. Given that most of the following is common structure in mysql queries. Even the example documentation for mysql followed this similar flow. Members who reply should negate from pointless internet banter. Its more worth your time, and my own to do so. Those who stayed on topic and assisted, I thank you.
For example:
$row = mysqli_fetch_row(mysqli_query($con, "SELECT test_table.points FROM test_table WHERE test_table.key = '" . $key . "'"));
if ($row[0] > 0){ // exists
Where $row will return a non-zero result if true. Otherwise 0 on false. There is little need to check mysqli_fetch_row and/or mysqli_query. Since checking $row in simplicity works fine. It is unneeded to check mysqli_fetch_row and/or mysqli_query individually in a general exists condition. It does accurately provide exist / does not exist results. There is no $result $row $query just $row.
The noted deviation to that normal flow was my desire to use call_user_func. And to poll in func and params through $_GET. Will be looking more at PDO. However, the clean code before exec should do alright job for now. Which is to clean before exec.
All in all, the code works just as it should. And have since written more to manage a mysql database. From write, write chunk, read, read chunk, delete, delete chunk.
Also to collect numbered records on request. For example say you have 6 records for the same John Smith. You can now collate and scan for differences in those records. Either for what you want, dont want, etc. Or if say you just want to blindly call the first 3 of those records for John Smith.
mysqli_fetch_row & mysqli_fetch_row fix :
FROM Calling $con outside function then into as per mysql. Which in mysqli does not work as expected. There was no error with the functions, over how $con was being handled.
TO Calling $con inside function with just the added global $con. May end up using $GLOBALS even for this.
Result : Calling $con outside function then in works fine in mysql. In mysqli it requires global be set within the function. ie global $con. Or it fails.
call_user_func non-critical error fix :
FROM call_user_func($func($_GET['user'],$_GET['key'],$_GET['points'],$_GET['type']));
TO call_user_func($func,$_GET['user'],$_GET['key'],$_GET['points'],$_GET['type']);
Result : Both lines execute correctly. From executed with a non-critical error. TO does the same thing, but with no following non-critical error.
Sample Output for both : user=MY_Name;key=34342$ee56i1;points=1234;type=
-- code removed as fixes solved the issues --
You are using call_user_func wrong read the manutal
call_user_func first parameter is the callback - in your case it's a function inside your class so it should be something like this:
If you have a non-static function in an object:
class Test{
public function doit($a){
echo($a);
}
}
$t = new Test();
call_user_func(array($t,'doit'),'asfaasfs');
and in static functions inside object:
class Test{
public static function doit($a){
echo($a);
}
}
call_user_func('Test::doit','asfaasfs');
You have a few problems.
$con is declared outside the class, and is thus not available inside the class. You need to pass it into the class (the better option), or specify it as a global (the quick+dirty option).
mysqli_fetch_row(mysqli_query($con,'...'))
This code is obviously converted directly from your old mysql_xx() code, but it's not great.
You're ignoring any possible error condition that is returned by mysqli_query(). This means that if it fails, it'll pass false into the mysqli_fetch_row() function, which will then fail with a meaningless error expects parameter 1 to be mysqli_result, rather than actually telling you what the error was in the query.
The thing is, because of my first point above, with $con not being set, mysqli_query() is failing, and this is why you're getting the error in mysqli_fetch_row().
Ideally, you should split this code out into multiple lines. Call mysqli_query() on its own, then do some error checking, then call mysqli_fetch_row() only once you know that the query actually worked.
Hope that helps explain what the problems are here. Solve those two points, and you should be well on the way to sorting the whole thing out.
Once you've got rid of those fatal errors, you should also take time to work on the problem that your code is vulnerable to SQL injection attacks. You're currently passing your $_GET variables directly into the query strings without any sanitisation. This will make your system very fragile and easy to hack. You should consider using Parameterised Queries, which is a feature of the mysqli library designed to make it easier to deal with variables in SQL queries in a safe and secure way.
Your class is pointless at the moment, perhaps stick to writing imperative style code as it will at least be cleaner.
At the moment, you should pass $con to your MYsql class to use itself as a resource, not try to access it as a global variable.
Your are not filtering your user's input either, this is dangerous and could lead to SQL injection attacks on your site.
I'd encourage you to read through these two articles, and once you grok them, I'd also encourage you to simply switch to using PDO with prepared statements. This will stop SQL injection attacks that your code currently allows.
http://net.tutsplus.com/tutorials/php/pdo-vs-mysqli-which-should-you-use/
http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
Is it common to use Exceptions to pass result states of operations or should I only use the function returns for passing values?
The operation results would be kept close to each other when I use exceptions, otherwise, using exceptions for errors and usin a return value for successful operations is another choice.
I was also thinking of extending the exception class and add more data to the validation result instead of returning an array from a validation function.
I am unsure and I'd like to hear your expericences and which method is more common.
edit:
currently I am thinking of doing something like this instead of using exceptions. (for archiving the experience.)
switch(login())
case: "success": /* success code; */ break;
case: "wrongpassword": $messagestoshow[]="wrong password"; break;
...
Is it common to use Exceptions to pass result states of operations or should I only use the function returns for passing values?
I don't think its common. I hope its not common.
The operation results would be kept close to each other when I use exceptions, otherwise, using exceptions for errors and usin a return value for successful operations is another choice.
There are two logical flows within your function, one is the expected one that ends returning a value on a successful operation, the other one has many exit points (one for each possible source of an exception). Using an exception to return a value, instead of using the function's return value, its simply an abuse.
The discussion for when is a situation exceptional is somewhat loose. Some language use exceptions to flag situations like end-of-iteration (Python), while in others throwing an exception could cause unwanted effects that should only arise in exceptional situations (C++).
It is a common design mantra to say that exceptions should not be used as GOTOs (essentially what you are doing in this case). Instead, you should rely on the return value.
Exceptions should always be treated as just that: exceptions. If something unexpected happens that the code is not prepared to handle (an exception), you should throw (and hopefully catch) the exception to handle it appropriately.
Using an exception for success breaks the control flow of your code. Even using an exception for non-exceptional errors (e.g. an expected validation failure) is abusive.
Where I work, we log all exceptions our website throws and I look these over every day. I'd be really annoyed if properly working code was adding a ton of exceptions to this list.
It's clearly an abuse of exceptions to signal that something succeeded, and I'd definitely not recommend it.
Exceptions should be used for exceptional circumstances, and success is not exceptional. Use a return value instead.
Exceptions are for exceptional events. It is highly inefficient to use them to simply return values from functions.