different number of results in SQL Statement when using die() - php

In a PHP script I do a MySQL Request where $SQL is a hardcoded SQL-SELECT statement:
$Result = mysqli_query($server,$SQL);
echo '<br>'.$SQL.'*'.mysqli_num_rows($Result);
#die('test');
The whole script is quite complex but running the code above prints the SQL-Statement and delivers 14 Result rows.
As I wanted to check the database directly at this point I added the above die() after the request. But doing so the SQL-satement now is delivering just 13 Result rows.
I know that cutting the code after the execution may change the state of the system as probable database operations in the cut off code won't come into effect anymore. But no matter if in the run before the die() has been active or not I always get 14 Results without a die() and always 13 Results with a die().
So my problem is: everytime when I run the code without the die() and and directly afterwards run the code again with the die() activated then until the die() statement there is no obvious difference in the code or the state of the database so the SELECT statement should always deliver the same number of rows... which it doesn't.
Can anyone think of a setting which makes this behavior understandable? I hope my explanation is not to wierd - otherwise I am happy to answer any questions. There is obviously a simple explanation which only I seem to miss...
Edit:
The problem I have is probably a bug I have hidden in a large piece of code. This surely is hard to answer especially if you have not got the full code. But maybe it helps if I reformulate my question to the following task:
Can you program a PHP code including the above snippet which shows the same behavior - so after each run (activated or not) it always delivers 14 Results with the die() deactivated and 13 runs with the die() activated? - of course allowing the sourcecode to analyze itself would be cheating...
Edit 2:
I found the reason of the Error. It is because the printing of PHP notices and warning in the code which accumulated during development and which in Firefox seem to lead to a problem if they reach a certain size before the <head> section. The die() case causes less of these because it breaks earlier and in fact doesn't even reach the <head>. If I mute notices both examples behave the same. What exactly lead to the error then I haven't examined... Sorry that I did not hint the error reporting in describing my question, but I had no clue that that might be the reason - especially as it was active in both cases....

Not an answer, just an example of what I mean by "simple, self-contained (,correct) example".
<?php
$server = setup();
$SQL = 'SELECT id,x,y,z FROM soFoo';
$Result = mysqli_query($server,$SQL);
echo '<br>'.$SQL.'*'.mysqli_num_rows($Result);
#die('test');
function setup() {
$server = new mysqli('localhost', 'localonly', 'localonly', 'test');
if ( $server->connect_errno ) {
die('!'.$server->connect_error);
}
$server->query('CREATE TEMPORARY TABLE soFoo (
id int auto_increment,
x char(255),
y char(255),
z char(255),
primary key(id)
)
') or die('!'.$server->error);
$stmt=$server->prepare('INSERT INTO soFoo (x,y,z) VALUES (?,?,?)')
or die('!'.$server->error);
$stmt->bind_param('sss', $x, $y, $z) or die('!'.$stmt->error);
foreach( range('a','n') as $x) { // fill in 14 records
$z = $y = $x;
$stmt->execute() or die('!'.$stmt->error);
}
return $server;
}
you just have to copy&paste it, adjust the MySQL connection data (credentials, host, database) and then run it.
In my case it prints <br>SELECT id,x,y,z FROM soFoo*14 as expected (since the setup() function added 14 records to the temporary table) regardless of whether the die() was there or not. So this example doesn't behave like your description, yet it contains the information (and the code snippet) you've provided. Something must be different on your side.
I've tested the script with php5.6.10 (win32) and MySQL 5.6.22-log (win32).

Related

Why `mysqli_query()` returns null? How can i figure it out?

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.

Simple DELETE query not working

This is something I should be able to do but I have been trying for the last hour to see the issue here but I can't. It is a simple delete function to delete an entry through the use of a ID tag. It is getting passed through the delete_category.php. If it helps my sql table is called blog_categories.
Its not throwing a error. Tried using echo mysql_error() on it but nothing. It simply acts like a dead link and refreshes the page.
Any help will be appreciated.
Blog.php:
function delete($table, $id) {
$table = mysql_real_escape_string($table);
$id = (int) $id;
mysql_query("DELETE FROM {$table} WHERE id = {$id}");
}
Linking delete function by:
Delete
Delete_category.php
<?php
include("../script/dbconnect.php");
include("../script/blog.php");
if ( ! isset($_GET['id']) ) {
header('location: cms.php');
die();
}
delete('blog_categories', $_GET['id']);
header('location:category_list.php');
die();
?>
So, this isn't a complete answer, but the comment fields are way, way too short to point you in the right troubleshooting direction.
Your code is broken, but not in the way you might expect.
GET requests have to be be idempotent. That is, they can't have side effects other than serving content. By having your delete functionality tied to a GET request, you are causing a side effect. This has some pretty severe consequences. Some browsers and caching mechanisms can pre-fetch links, for example. Also think about what a search spider would end up doing if it crawled that page.
Turn that GET into a POST. Perhaps use a form and a button instead?
It's awesome that you're using mysql_real_escape_string, but your use of it here is incorrect. mres is designed to encode character data as part of a string. You are using it on an identifier -- a table name. Identifiers do not share the same escaping semantics as strings, especially when used outside of quotes.
As long as the first argument to the delete function never comes through users, you can skip mres here.
You aren't checking the result from mysql_query. Sayeth the manual:
For other type of SQL statements, INSERT, UPDATE, DELETE, DROP, etc, mysql_query() returns TRUE on success or FALSE on error.
You're throwing away the result. You should check that it isn't false and then call mysql_affected_rows to make sure that one and only one row was removed. If mysql_query was false, then you can check mysql_error.
After making these changes, you then need to alter your delete_category.php script to assist in troubleshooting:
Add the following two lines to the very top:
error_reporting(-1);
ini_set('display_errors', true);
Change all of the headers to echos. An immediate redirect is going to mask any errors.
Use exit instead of die. While they do the same thing, the use of die is frequently used exclusively in the context of "something went so wrong that I have to exit now," vs exit, which is just, well, uh... exit.
Anything that's actually going wrong should then be pretty darn obvious.
If you still aren't seeing anything incorrect happen, and the rows still aren't being deleted, try adding a SELECT COUNT(*) FROM ... before and after the delete, using the same table name and WHERE clause. That will help us troubleshoot further.
Long term, you really want to begin switching from mysql_ PDO or mysqli. The next major release of PHP, version 5.5, is deprecating the mysql_ family of functions.

exit, exit(), exit(0), die(), die(0) - How to exit script

I believe that all of these (and even die() or die(0)) are identical. If they are not identical, which is preferred for exiting a script successfully? If they are identical, is there any preferred standard to indicate successful script completion? I tend to use exit;.
EDIT: All of the answers have "die() and exit() are identical" even though I say that in my question. I updated to the title to hopefully make it clearer that this is NOT my question. I want to clearly indicate success from a command line script.
These are all identical. I'm pretty sure die() is just a straight-up alias to exit(), but even if it isn't, it still acts identically.
When one of these functions is given a string argument, it prints out the string before terminating the process. When it encounters an integer under 255, that integer is considered the return code for the process, which gets passed back to the process which invoked the PHP script. This is particularly useful when writing command line applications (PHP isn't web-only!).
As far as the difference between exit, exit(), and exit(0), there really is none. There is definitely no difference between the first two because exit is technically a language construct, not a function, so it can be called with or without parentheses, just like echo. Returning a code of 0 means "this program ran successfully/without errors", and while I don't know what exactly happens when you don't pass an argument, PHP.net says that an argument-less exit indicates success, so I would bet it returns 0, though again PHP.net doesn't show a default for the argument.
As several people have mentioned, die() and exit() are exactly the same.
If you look at the PHP documentation, there are two options for arguments:
An numeric value. This is only useful if you are using PHP from the command line, as opposed to a web server. A value of zero indicates success. Nonzero indicates a failure condition occurred.
A string value. This will be displayed to the browser when the exit occurs.
Instead of die() or exit(), I recommend using exceptions and a custom top-level exception handler to manage failure conditions.
You have more flexibility that way to do things like automatic error logging. Also, if you're using PHP to implement a JSON API, this exception handler can hand back a valid, error-indicating JSON snippet instead.
I would say that in regards with a better semantics die($arg); should be used for an abnormal or unexpected termination, even when -of course- you still have caught it. And exit($arg); should be used for a normal (expected / controlled) end of a process, like in break; for a for or while or a switch structure but with a definitive end.
Nevertheless .. I personally often use a general if { } else { } structure to control different branches of huge processes or output buffering so not having to use "exit" ..
I also use die($arg) in simple error-catching semantics like in
$db = mysql_connect([$args]) or die ($error); ...
die(); is just a synonym for exit(); and is functionally identical.
The standard way is to use exit code zero to signify success, and anything else to denote an error condition.
die() is typically used to kill the script with an error output:
die("There was a fatal error");
where-as exit is typically used as a successful exit (At least in my coding)
The PHP Manual says that the functions are identical.
I will get downvoted to hell, but in some cases when hacking in CLI, we do not want the program to get killed, while not wanting to continue the full execution.
Here the goal is to avoid making api calls to a separate hand-point file. Say I have a nice play button in my interface, that execute system calls.
Example 1: The program get killed after the job , no datas returned. This is not wanted.
if ($_GET["play"] != ""){
// Some job
exit;
}
/* Huge amount of data*/
Example 2: The program still runs, feeding the whole data in the GET request. This is unnecessary on this case. This is slowing down the browser with all the data, that he has already.
if ($_GET["play"] != ""){
// Some job
}
/* Huge amount of data*/
Example 3: The program still runs, no data returned as expected, the play command had been executed, but the whole data set get parsed, this is unnecessary job, can slow down php/the machine.
/* Huge amount of data*/
if ($_GET["play"] != ""){
// Some job
}
Example 4: The program still runs, no data returned as expected, the play command had been executed, the whole data had not been parsed, php returned super quickly 200OK with an empty response, as expected. Everyone happy!
if ($_GET["play"] != ""){
// Some job
goto END;
}
/* Huge amount of data*/
END;
Yes! Using GOTO, sometimes is to be considered -as the best to do 🔨 -!
https://www.php.net/manual/en/control-structures.goto.php
die is exactly equivalent to exit.
From the manual:
If status is an integer, that value will be used as the exit status..
This is only useful if you have some sort of wrapper that does something based on the exit status. Unless you have a specific need to report an exit code to the outside world, just exit;.

In PHP, does suppressing error output of a function (via #) affect performance if no error occurs?

Like most of our code base, our mysql handling functions are custom built.
They work very well and include a number of logging forks.
A simplified version of our query execution function looks like this:
if(!$result=mysql_query($query)){
file_put_contents(QUERYLOG,'Query '.$query.' failed execution');
}
This is overly simplified, but you get the basic idea: If queries fail, they will be logged to a separate query log.
This is a great way of keeping track of any queries that need to be looked at.
My question is as follows:
With the above, the tiny problem is that if a query fails both our query log, AND our php log will be stamped with the error as a mysql_query (... or mysql_connect, mysql_select_db, etc ...) will produce a php error.
What we want to do is surpress the php error via:
.... $result=#mysql_query($query ....
So, as far as the question goes:
Does using the # error suppression mechanism in php cause any performance impacts if no error is produced? Or does it only affect performance if an error is produced?
I know I know, micro optimization, but as you can guess, or query execution function is used millions of times a day, so even a small performance hit is worth examining.
made a little "research"
$s = microtime(true);
$a = array('1','2');
$b = $a[1];
echo microtime(true)-$s;
gives 1.1205673217773E-5
and if i use $b = #$a[1]; i get a bit more: 1.5974044799805E-5
so: yes, there is a difference, but no, you should not bother.

need some simple help understanding a bit of pre-PHP5 code

I was turned on to nstrees from another question, and have been working through the script. It was last updated in 2005 and relied on some stuff that has since apparently been deprecated like HTTP_POST_VARS which I wasn't immediately familiar with since I've been doing PHP for only a little less than a year.
Anyways, the coding style seems weird to my rookie eyes, and I'd like a second opinion on what part of this function does:
// returns the first node that matches the '$whereclause'.
// The WHERE clause can optionally contain ORDER BY or LIMIT clauses too.
function nstGetNodeWhere ($thandle, $whereclause) {
$noderes['l'] = 0;
$noderes['r'] = 0;
$res = mysql_query("SELECT * FROM ".$thandle['table']." WHERE ".$whereclause);
if (!$res) { // problem area 1
_prtError();
} else {
if ($row = mysql_fetch_array($res)) { // problem area 2
$noderes['l'] = $row[$thandle['lvalname']];
$noderes['r'] = $row[$thandle['rvalname']];
}
}
return $noderes;
}
In the above code I marked the spots I'm not quite sure about as // problem area x, everything else is the original script.
Regarding PA1, is that just a check on whether the query was successfully run?
And PA2, NetBeans gives me a warning "Possible accidental assignment, assignments in conditions should be avoided." ... so I promptly changed that from = to == and of course broke the script, heh.
Thinking about it, I guess it's just another error check on $res, this time to make sure that some data was actually returned?
Lastly, is this bizarre PHP or am I just too green to grok it?
Thanks dude(tte)s!
Problem Area 1 is exactly what you think it is. It checks if the query ran successfully. Look at the documentation for mysql_query (since you use Netbeans you can also highlight the function name in the editor and hit F2 to get an inline popup). You're looking for the "Return Values" section. Over there it says it will return FALSE (the boolean FALSE) on any errors.
Checking
if (!$res)
is the same as checking for
if ($res == false)
Ideally you should be checking for
if ($res === false)
because it's safer since PHP is very relaxed about variables == false, but I'd rather not confuse you with that right now. If you'd like you can start by reading about strong typing.
Problem Area 2 is pretty common but will show a warning in Netbeans, yes. What it's doing is assigning a value from mysql_fetch_array() into $row, and checking if that is now true or false, while also letting you use that same value now in $row in the following code block inside the if().
I assume this code can load articles then sort them into a 'left-right' array so it can be printed in a two column layout. Maybe. :)
Yep, PA1 is checking if the query was successful or not. PA2 is simply fetching the actual row.
if (!$res) { // problem area 1
mysql_query returns a false if it fails to execute the SQL query. This is basically a test for not (!) any value other than false, so the if test will match if there was an error in mysql_query and execute the print error branch of the code
if ($row = mysql_fetch_array($res)) { // problem area 2
Assigns the next row from the resultset to $row; or sets $row to false if no more rows in the resultset, in which case the "if test" will be false

Categories