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
Related
I am taking over the maintenance of an old web site and came across this confusing syntax for processing a form that I have never seen before, and I am not exactly certain what it does:
foreach (array('address','comments','country','email','mail_content','name','title') as $vuln)
{
isset($_REQUEST[$vuln]) and $_REQUEST[$vuln] = htmlentities($_REQUEST[$vuln]);
isset($_GET[$vuln]) and $_GET[$vuln] = htmlentities($_GET[$vuln]);
isset($_POST[$vuln]) and $_POST[$vuln] = htmlentities($_POST[$vuln]);
isset($$vuln) and $$vuln = htmlentities($$vuln);
}
It's the "and" that is throwing me - I read it as "if variable is set convert it to htmlentities, but why is there an "and" in there?
Finally what does the last line do?
isset($$vuln) and $$vuln = htmlentities($$vuln);
It's using the operator precedence rules of PHP in an unusual way.
If you have an and statement, PHP will stop processing it if the left side is false - there's no need to check the right hand side, because it won't make a difference to the end result. (The converse is also true for an or statement if the left hand side is true.)
So the coder that wrote this is using it as a shorthand for:
if (isset($_REQUEST[$vuln])) {
$_REQUEST[$vuln] = htmlentities($_REQUEST[$vuln]);
}
They've save a small amount of typing, at the cost of making the code slightly harder to read. It's good practice to use isset to make sure that your array values are set before you use them, which is why the check is there.
As to the last line; logically, it's doing the same as the above, but with a variable variable. The first time through, $vuln will be set to the first item in your array, which is address - the final line of code is checking to see if there's a variable called $address, and if so, set its value to htmlentities($address).
That's what the code is doing. Why it's checking REQUEST, GET, and POST is beyond me.
Hi These are the nothing but the shortend form.
isset($_REQUEST[$vuln]) and $_REQUEST[$vuln] = htmlentities($_REQUEST[$vuln]);
above line means
if(isset($_REQUEST[$vuln])){
$_REQUEST[$vuln] = htmlentities($_REQUEST[$vuln]);
}
Also the $$vuln is a reference variable its checking the same that if reference variable is set then assign it value
isset($var) and <statement goes here that uses $var>;
This basically only executes the <statement ...> if the statement preceding and (in this case isset($var)) evaluates to true. This happens because if anything is false before a and, there's no need to evaluate (or execute) the rest. This works similarly to:
if (false && condition) { ... }
The condition will never be evaluated, since no matter what its value evaluates to, the if condition will always evaluate to false.
A more readable alternative for the first example:
if (isset($var)) {
<statement goes here that uses $var>;
}
As pointed out in the comments by #chris85, see $$variable.
An example of a variable variable:
$vuln = 'abc'; /* Regular variable assignment */
$$vuln = 'def'; /* This is "equivalent" to $abc = 'def'
* because $$vuln expands to $<contents of $vuln>,
* therefore $abc is assigned with 'def'.
*/
/* $abc is now a variable with 'def' as its value */
It might be easier to comprehend as the following, for the first iteration through the array:
<?php
if(isset($_REQUEST['address'])) {
$_REQUEST['address'] = htmlentities($_REQUEST['address']);
}
if(isset($_GET['address'])) {
$_GET['address'] = htmlentities($_GET['address']);
}
if(isset($_POST['address'])) {
$_POST['address'] = htmlentities($_POST['address']);
}
if(isset($address)) {
$address = htmlentities($address);
}
It looks to me like legacy code that probably was a replacement for (or perhaps in addition to) 'magic quoting' when 'register globals' was turned on. Probably so they could do some pseudo escaping of variables before database inserts and or page echos.
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).
php/mysql noob with question. MYSQL does not seem to have a preferred way to store boolean values. I decided to go with Tiny(int) at the suggestion of someone on a message board who said this is equivalent to True/False. I would think that True =1 and False =0...maybe that's assuming to much... Anyway put 1 values in mysql dbase for testing. They showed up in phpAdmin as "1" for what that's worth.
I'd like to retrieve these values and if TRUE show picture and if false, not show it. So after connecting with dbase and running successful query that returns other text values fine, I wrote...
if ($row['email'] == TRUE)
{
echo "<img src='images/email.png'>";
}
Alternatively in place of TRUE, I've tried 1, '1' "1" 'TRUE' etc.
If I just echo $row('email'), I get 1. However, the above logic does not work. The condition is never meant and the image never shows. I tried turning it around with != but still can't get it to work. From what I've read, booleans in MYSQL can be a bit flaky but this seems pretty basic.
Note. With above code, there is no error. It just never evaluates the statement in parentheses as true to execute conditional. Could it be a syntax error??? or what am I missing.
Thanks for any suggestions!
If i understand correctly your using
if($row['email'] == 1){
echo "<img src='your-path.jpg'></img>";
}else{
// do nothing if false
}
I decided to go with Tiny(int)
That's exactly how it's done by millions around the world.
I would think that True =1 and False =0
That is how you should interpret it.
if ($row['email'] == TRUE)
does not work
This should absolutely work and can be tested simply with:
$row['email'] = '1';
echo $row['email'] == true; // output: 1
Double check the contents of $row, i.e., var_dump($row) to ensure that the data is being properly gathered from the database. Check for any errors returned from the database. Also check for errors returned by PHP by placing this at the top of your script:
ini_set('display_errors', 1);
error_reporting(E_ALL);
I use enums, because they're more readable in certain situations; especially when dealing with an old table.
Ie, "isDeleted" can have values of 1/0 or as an enum, "Yes/No" or even better: "Live/Deleted."
All three describe the same state, but the last example punches you in the face more heavily.
Only complication is inputting it, but, booleans are the bane of all that is HTML anyway. MySql queries for saving are fairly sensible:
mysql_query( sprintf(
"update table set isDeleted='%s' where id=3",
($myvalue === true ? 'Live' : 'Deleted')
));
In an effort to tidy up my code, I've encapsulated my database reads into its own function, which accepts a SQL command for the argument, as well as an optional $getArray argument which specifies whether I am returning an array as the result (true for SELECT, false for UPDATE, etc).
function readDB($sql, $getArray = false)
{
$conn = odbc_connect('myAccessDataBase', '', '');
if (!$conn)
return exit('Connection Failed: '.$conn);
if ($getArray = false)
odbc_exec($conn, $sql);
else
{
$res = odbc_exec($conn, $sql);
if (!$res)
return exit('Error in SQL');
return odbc_fetch_array($res);
}
odbc_close($conn);
}
The code above works as expected except for one small caveat. If I am performing an UPDATE vs a SELECT, I get a warning due to $getArray being set to false:
Warning: odbc_fetch_array() [function.odbc-fetch-array]: No tuples available at this result index in C:...\functions.php on line 14
I understand the warning, which makes sense if that line were to actually be executed, however it is not. My question is in regards as to why PHP is evaluating the contents of the else portion of my if statement, which is not even being hit during runtime. I understand that the UPDATE cannot return an array, hence why I am evaluating $getArray to determine whether I expect such a return. What can I do to circumvent this warning? Regardless, I am still pretty fresh with my PHP, and am probably going about this the wrong way anyhow. Cheers!
You're setting the variable TO FALSE instead of evaluating it FOR FALSE If you change this line:
if ($getArray = false)
to
if ($getArray == false)
It should work.
edit
On another note, you should do your test in reverse. Instead of testing for false, test for true and THEN have an else. It makes a little more sense logically for anyone coming in to look at your code later.
Instead of If this IS NOT the case then do this it makes more sense to say if this is the case, do this
So switch your code blocks around and test:
if ($getArray)
The line
if ($getArray = false)
must be
if ($getArray == false)
I've been trying to change some code for a validation script so that it doesn't include goto, as I want to run my scripts on a webhost, and unfortunately most of them don't really have 5.3 or later.
The code is meant to use a value generated by rand for a unique validation number. If it finds it already in the DB, it will append 1 on to the number as many times as it needs to until it finds a usable number. Pretty straightforward. I know it's terrible practice for a MySQL query, but it's really just a simple script for practice.
The code is as follows:
function gen_val($val)
{
$query = mysql_query("SELECT val_id FROM users_tmp WHERE val_id=$val");
$row = mysql_fetch_array($query);
if ($row[0]==$val) {
gen_val($val+1);
} else {
return $val;
}
}
$val_x=gen_val(rand());
This returns a value '0' if the value already existed in the DB. Function works fine if there's no similar value already, so I think there's a problem with the function recursing. I don't think I really know how to use it properly, so please go ahead and educate me.
Cheers.
Asher
You forgot to return the result of your recursion.
return gen_val($val+1);
Correct me if I'm wrong, but you want to get a unique ID for each user. MySQL has this feature.