Odd php error..
Thomas Fjellstrom

Yes, I suck at coming up with topics, so sue me ;)

I've been working on two php apps today, and both are giving me the same headache. Some how, php is caching the code and only refreshing when it feels like it. And it doesn't happen all the time, I was making good progress all afternoon till a bout an hour ago...

Heres the error I get from php:

[Thu Mar 29 18:29:59 2007] [error] [client 192.168.1.20] PHP Fatal error:
mysql error: [1146: Table 'moodle.mdl_teachmeto_activeusers' doesn't exist] in
EXECUTE("UPDATE mdl_teachmeto_activeusers SET lastactivity = '2007-03-29 18:29:59' WHERE userid = '5'")
in /var/www/.../htdocs/lib/adodb/adodb-errorhandler.inc.php on line 77, referer: http://.../chat/

And the funny thing? its right, that table doesn't exist, but it doesn't exist that way in the php code either. grep finds NO references to any mdl_teachmeto_* tables.

I'm stuck trying to figure out why php+apache can't seem to notice the code has changed, and hacking with a couple third party apps and libs. All in JS and PHP, neither of which I like very much. ::)

BAF

Well, you can specify the DB prefix in moodle, IIRC, so check for teachmeto_ references, as the mdl would be pulled from a configuration.

And, unless you have some type of caching setup, it will always execute the PHP every time the page is requested.

bamccaig

Can you tell us anything else? Maybe give us some code? What DBMS are you using? It appears related to ADOdb or the database.

Thomas Fjellstrom said:

"UPDATE mdl_teachmeto_activeusers SET lastactivity = '2007-03-29 18:29:59' WHERE userid = '5'"

Is that your SQL or something from PHP? Should the 5 be in single-quotes...?

Thomas Fjellstrom
Quote:

Well, you can specify the DB prefix in moodle, IIRC, so check for teachmeto_ references, as the mdl would be pulled from a configuration.

Ah, the teachmeto stuff is an addition. Its not part of moodle, but it does access some of moodle's dirty bits.

Quote:

And, unless you have some type of caching setup, it will always execute the PHP every time the page is requested.

Good to know.

Quote:

Can you tell us anything else?

Thats all I can think of, it just decides not to notice that some code has changed.

Quote:

Maybe give us some code? What DBMS are you using? It appears related to ADOdb or the database.

Using mysql and ADODB, through moodle's api.

Quote:

Is that your SQL or something from PHP? Should the 5 be in single-quotes...?

Its from php, or possibly moodle's api.

BAF

That SQL is fine, as far as the 5 being in quotes goes.

Thomas Fjellstrom

Lets chock that one up to stupidity (mostly on the part of the original programmer >:E)

Now I have another problem that I don't quite get:

[Thu Mar 29 20:42:06 2007] [error] [client 192.168.1.20] PHP Catchable fatal error:
Object of class stdClass could not be converted to string in
/var/www/.../htdocs/chat/chat.php on line 345, referer: http://.../chat/

Quote:

$teachers = array(); ...
/* line 345 */ return array_unique($teachers);

bamccaig
BAF said:

That SQL is fine, as far as the 5 being in quotes goes.

It's like a dynamically typed SQL!? {runs away crying}

Are most SQL implementations like that or only MySQL's?

BAF

That almost sounds like a running-php4-on-php5 or php5-on-php4 type of error.

Quote:

It's like a dynamically typed SQL!? {runs away crying}

If you knew SQL you would know that (IIRC) you are actually supposed to quote everything like that, for security reasons.

bamccaig

I do know SQL and I've never seen that before. In fact, if I'm not mistaken SQL Server will return errors if you quote a numeric field.

What security benefit is there to quoting everything?

BAF

Apparently I am wrong. I'll take note that you are not "supposed" to quote your integral types. As far as I know it works either way, however.

Thomas Fjellstrom

ok, It may be a php version error, the person that wrote this crap up and ditched on my friend...

1 function tmt_findMyTeachers()
2 {
3
4 global $USER;
5 $isTeacher = 0;
6 $teachers = array();
7
8 $COURSES = get_my_courses($USER->id);
9
10 foreach($COURSES as $COURSE)
11 {
12
13 $context = get_context_instance(CONTEXT_COURSE, $COURSE->id);
14 $myteachers = get_role_users(3, $context);
15 $myteacher2 = get_role_users(4, $context);
16
17 if ($myteachers)
18 foreach ($myteachers as $teacher)
19 array_push($teachers, $teacher);
20
21 if ($myteacher2)
22 foreach ($myteacher2 as $teacher)
23 array_push($teachers, $teacher);
24
25 }
26
27 return array_unique($teachers);
28
29 }

From my Very limited knowledge of php, I'd say that looks ok...

bamccaig

I looked it up on dev.mysql.com. Apparently MySQL will convert between types when necessary. So if you tried:
SELECT 1 + '1' AS Sum;

Result should be:
+-----+
| Sum | 
+-----+
|   2 | 
+-----+

That's why I ran away crying..........

I don't like that... Dynamic typing is evil...

BAF

It looks like get_role_users returns an array of classes or something, and array_unique has to be able to convert everything to strings. That's the only possible issue I can see with that code.

[edit]
Add a 'var_dump($teachers);exit(0);' before the return, and paste what it prints.

bamccaig

[Reads PHP function]

{again runs away crying}

Thomas Fjellstrom

The problem with trying to var_dump it, is it only works through AJAX ::) its quite hard to get it to pass in some error/debug crap.

BAF

Then you could do:

file_put_contents('teacher.log', var_export($teachers));

then post teacher.log.

bamccaig
  • Why define an $isTeacher variable and not use it?

  • What does get_my_courses() return?

  • What does get_context_instance() return?

  • What kind of variable name is $context?

  • What does get_role_users() return?

  • Why create two $myteacher[s] variables if the second isn't really used until you're done with the first?

  • Through all of the confusion this function brings me there are no comments!?

Thomas Fjellstrom

Its empty..

And the get_roles_user functions seem to get the roles in an array of something casted to (object)s.

bamccaig: this is not my code, please believe me ;(

bamccaig
Thomas Fjellstrom said:

And the get_roles_user functions seem to get the roles in an array of something casted to (object)s.

The roles of what?

Thomas Fjellstrom
Quote:

The roles of what?

Of the user? Like if you're a teacher, or student, or lesbian, etc.

edit: actually thats not true...

They return other user objects that are assigned to that "role" (in this case, two forms of teacher).

BAF
Quote:

  1. Why define an $isTeacher variable and not use it?

  2. What does get_my_courses() return?

  3. What does get_context_instance() return?

  4. What kind of variable name is $context?

  5. What does get_role_users() return?

  6. Why create two $myteacher[s] variables if the second isn't really used until you're done with the first?

  7. Through all of the confusion this function brings me there are no comments!?

Don't ask him, he didn't write it. Nobody really knows what's going on. :P

Quote:

Its empty..

And the get_roles_user functions seem to get the roles in an array of something casted to (object)s.

How could it be empty and still give those errors? This baffles me. What if you just try return $teachers; dropping the array_unique() call temporarily to see if it at least approaches how it is supposed to work?

bamccaig
BAF said:

Don't ask him, he didn't write it. Nobody really knows what's going on.

He has more information than I do... I'm just trying to grasp what this function is supposed to do...

BAF said:

What if you just try return $teachers; dropping the array_unique() call temporarily to see if it at least approaches how it is supposed to work?

What if you rewrote the system, just to be sure.....?

Thomas Fjellstrom
Quote:

What if you rewrote the site, just to be sure?

I wish, It'll take less time to just find the last bits that are going haywire.

BAF

Why rewrite code when you can fix it? The new code won't look much different, and that code at least did something at some point, so it's easier just to fix it, IMO.

Anyway, I'm off to bed. I'll post more help in the morning.

bamccaig
BAF said:

Why rewrite code when you can fix it? The new code won't look much different, and that code at least did something at some point, so it's easier just to fix it, IMO.

Have you ever heard of The Daily WTF, recently renamed Worse Than Failure?

Everyday you'll find examples of how the code DIDN'T work at some point (i.e. NEVER worked), and yet it's still part of an enterprise level system... If the guy that wrote that function had a lot to do with the site you might be better off rewriting it from scratch.

Patching it to work won't improve maintenance in the future. It'll It might speed up launch day (possibly implementing buggy code), but eventually maintenance might outweigh the benefits of keeping code now.

And I hope that the new code would look much different. {smiley - when will EFW be over with!?!??!?}

Thomas Fjellstrom
Quote:

eventually maintenance might outweigh the benefits of keeping code now.

Won't be my problem. :P Neither I or my friend will likely have anything more to do with the people that hired him/us.

I also don't know that much php, so uh, yeah...

Onewing

I found out about thedailywtf from a.cc. In fact, the majority of the sites I know now came as a reference from a.cc, like askaninja.com (which has apparently become really popular lately).

Matthew Leverton
Quote:

[Thu Mar 29 20:42:06 2007] [error] [client 192.168.1.20] PHP Catchable fatal error:
Object of class stdClass could not be converted to string in
var/www/.../htdocs/chat/chat.php on line 345, referer: http://.../chat

I would bet that some MySQL result is trying to be used as an array index somewhere. Something like:

$foo = mysql_foo(); // returns an object
$array[$foo] = 'boom';

It tries to call $foo->__toString() and it doesn't exist, so something bad happens. From your code, I don't see why it would happen. But my instincts say that is the problem.

It's possible that "mysql_foo()" is returning some sort of error (as an object), instead of some expected value as a string. No error detection of course, so everything goes to hell.

For example:

<?php
        $foo = (object)'Error!';
        $bar['test'.$foo] = 'Hello.'; // won't work
?>

"Catchable fatal error: Object of class stdClass could not be converted to string in foo.php on line 3"

Thomas Fjellstrom

I'll look into it. Though its a LOT of php code to dig thorough. All of the Moodle api, the bits of code done by the genius that coded the function above, and ADODB itself.

Is there a way to get php and ADODB to actually print out a backtrace like you get in C? I need to see the context of what was called from where. That ADODB error is absolutely useless since It makes me guess where it originated from.

Thanks

Matthew Leverton

You could try throwing an Exception. I think that dumps out the function stack.

throw new Exception("foo");

I also wouldn't mind taking a look at it via SSH. But that offer is only valid for the next few hours while I'm waiting to get sleepy...

Thomas Fjellstrom

I'm not sure you want to... But ok. PM ahoyhoy.

edit:
Oh my, more problems:

[Fri Mar 30 17:32:17 2007] [error] [client 192.168.1.20] PHP Notice:
Trying to get property of non-object in /var/www/.../htdocs/chat/chat.php
on line 436, referer: http://.../chat/

here's the output from dumping $user:

object(stdClass)#213 (6) {
  ["id"]=>
  string(1) "4"
  ["isteacher"]=>
  string(1) "1"
  ["isloggedin"]=>
  string(1) "1"
  ["logindate"]=>
  string(19) "2007-03-29 20:02:49"
  ["lastactivity"]=>
  string(19) "2007-03-29 20:02:49"
  ["temporary"]=>
  NULL
}

bool(false)

And this is the line:
if (isset($user) && $user->isloggedin == "1") && (isset($user->lastactivity))) {

Matthew Leverton

The bool(false) would probably be from a second var_dump indicating the user isn't set. I'd try this:

if (isset($user) && $user && $user->isloggedin == "1") && (isset($user->lastactivity))) {

Thomas Fjellstrom

Woot. That worked great, and eventually I got the stupid thing working. A nice little Ajax chat thing.

Now I'm trying to mess with the css, but the css doesn't seem to be cascading. Or somehow Firefox is caching the css even when I clear the cache and restart :o I look at the code with firebug, and nowhere does it see my modified items. Then again, konqueror won't notice them at all either :(

Of course a lot of the stuff thats not changing is all generated in javascript.. Could that be the reason? I dunno, it sees the original css fine :o

bamccaig
Matthew Leverton said:

if (isset($user) && $user && $user->isloggedin == "1") && (isset($user->lastactivity))) {

The only time I've ever had a use to check if a variable was set in PHP was when I was checking for GET and POST variables from a Web page. And when I did, I avoided the ugly use of isset() and just went straight to a boolean condition:

    if($_POST['btnSubmit'])
    {
        // Do stuff
    }

Maybe there is something wrong or unreliable about doing that? It seems you had to check that anyway...

    // Why bother checking isset($user)...
    if(isset($user) && ...)

    // If you have to also evaluate just $user...
    if(... && $user && ...)

    // Might this work instead?
    if($user && (bool)$user->isloggedin && $user->lastactivity)

Thomas Fjellstrom

It might, but its working now, and cleaning up the code really isn't a priority. Whats left now are a few feature additions, and its out of my hands.

Thanks for the help :)

I still would like to figure out why the page is ignoring css changes, even with !important tagged on them. :(

Matthew Leverton
Quote:

// Why bother checking isset($user)...

Because it is a horrible programming practice to assume a variable exists when you don't know if it does. It triggers an E_NOTICE in PHP, which every responsible developer cares about.

Thomas Fjellstrom

I agree. You should see the notices I get from the Syntax Highlighting plugin for mediawiki :o

edit: Clutter in the logs is a pain.

BAF
Quote:

edit: Clutter in the logs is a pain.

Why is php logging to your log files? And why don't you use error_reporting(E_NONE);?

Quote:

The only time I've ever had a use to check if a variable was set in PHP was when I was checking for GET and POST variables from a Web page. And when I did, I avoided the ugly use of isset() and just went straight to a boolean condition:

if($_POST['btnSubmit'])
{
// Do stuff
}

$_REQUEST works great for that. Also, as ML said, you shouldn't assume variables are set. Much better to just check if the variable isset().

Thomas Fjellstrom
Quote:

Why is php logging to your log files? And why don't you use error_reporting(E_NONE);?

Because many php coders are inexperienced at best... Using error_reporting willy nilly in their source.

bamccaig
BAF said:

$_REQUEST works great for that. Also, as ML said, you shouldn't assume variables are set. Much better to just check if the variable isset().

I wasn't assuming the variables are set. I was checking them with a simple boolean condition. If the form wasn't submitted, for example, the following if statement's boolean condition would result in false and never execute:

    if($_POST['btnSubmit'])
    {
        // Do stuff...
    }

Alternatively, if the form was submitted it should result in true and execute.

That might be bad example, being that I think the submit button only transmits as POST data if the button is pressed - at least I think that is true for ASP's Response.Form() (haven't done PHP in months). Alteratively, though, you should be able to check any field that doesn't result in 0 or empty (which would result in false). For example:

    if($_POST['txtUsername'] && $_POST['pwdPassword'])
    {
        // Query User table...
    }
    else
    {
        // Handle bad login...
    }

I know about the $_REQUEST[] superglobal. The use of $_POST[] had nothing to do with what I was referring to. Besides, if your application wasn't designed to accept GET data there's really no point using $_REQUEST[].

In fact, the risk of name collisions is greater if you do use $_REQUEST[] than if you specify the transmission method.

It could also theoretically be easier to attempt malicious activity on your site if you use $_REQUEST because instead of creating a Web page (or using software) to transmit POST data to your site they can simply try appending to the query string...

Matthew Leverton
Quote:

Why is php logging to your log files? And why don't you use error_reporting(E_NONE);?

Errors, warnings, and notices are good indicators that something is going wrong. Silently ignoring them doesn't make your code magically better.

Quote:

If the form wasn't submitted, for example, the following if statement's boolean condition would result in false and never execute:

It would also trigger an E_NOTICE; thus it's a bad practice.

Thomas Fjellstrom

Unfortunately you get a warning if you access a array/hash index that doesn't exist. Mainly because you shouldn't be accessing undefined variables ;)

In my perl code, I specifically use the most anal warning/error mode: use warnings; use strict;
Which help cut out a lot of possible errors with using references, undefined variables, and whatnot.

bamccaig
Matthew Leverton said:

It would also trigger an E_NOTICE; thus it's a bad practice.

Which can be limited by only storing necessary data in session variables. On your live server you can limit error reporting to serious errors, excluding the maybes such as E_NOTICE that can occur during normal execution.

If it shouldn't be done that way then PHP shouldn't allow it. I agree it's not pretty, but then neither is isset(). Besides, what scripting language is pretty?

That's why I prefer programming in C++ to any kind of Web development. 8-)

Today I attempted to test some PHP theory and realized that PHP isn't being processed by my Apache Web server... Now I have to figure out what's wrong and how to fix it. I was sure that I had run PHP scripts on this system before... Why not anymore!? :'( To make it worse I've been drinking Canadian beer so I'm not at my best...

BAF
Quote:

I wasn't assuming the variables are set.

Quote:

    if($_POST['btnSubmit'])
    {
        // Do stuff...
    }

Looks like an assumption to me. You are assuming $_POST['btnSubmit'] is set and contains a boolean value. The proper solution here is to run it through isset. It will return true if the form was submitted, false otherwise (unless the button press was spoofed).

bamccaig
BAF said:

Looks like an assumption to me. You are assuming $_POST['btnSubmit'] is set and contains a boolean value. The proper solution here is to run it through isset. It will return true if the form was submitted, false otherwise (unless the button press was spoofed).

If $_POST['btnSubmit'] isn't set it won't execute the if block. If it is set it will, unless maybe you set the value (the label) to an empty string or 0. Feel free to try it. I wrote a shopping cart project like that and it worked fine.

In other words, I'm not assuming that $_POST['btnSubmit'] is set. I'm acknowledging that if it's not set the condition will fail. $_POST['btnSubmit'] doesn't contain a boolean. It's been a while since I've done PHP, but I believe it will contain either 'btnSubmit' or whatever the value attribute was set to ('Submit', for example)(btnSubmit was an <input type="submit" .../>).

It may or may not require the error reporting to be configured lightly forgivingly in order to avoid displaying error messages on the page. If so, it's not really a problem since the errors displayed are more like 'maybe errors' (not a problem) and for a live server you should have errors turned off anyway (users don't need to see PHP warnings/errors, and they shouldn't exist on your live system anyway, right? ::)).

Matthew Leverton
Quote:

In other words, I'm not assuming that $_POST['btnSubmit'] is set.

You are so! If it's not set, an E_NOTICE will be triggered. No one is saying that your assumption is changing the logic at all. However, your logs will be flooded with bogus E_NOTICEs, and you won't be able to spot when an E_NOTICE really is trouble. By using isset(), you avoid generating the E_NOTICE.

Quote:

users don't need to see PHP warnings/errors, and they shouldn't exist on your live system anyway, right?

You're absolutely right on the first half. Users shouldn't see the errors. The errors should go to log files.

You're partially right on the second half, but your conclusion is incorrect. Errors shouldn't occur on the live system, but if they do, you better be able to track it! By programming in such a way that all E_NOTICEs indicate problems, it's so much easier to debug problems.

Purposely writing code that triggers E_NOTICE is simply bad practice.

bamccaig

** PREPEND **

Matthew Leverton said:

You are so!

I'm not assuming that the variable is set. I'm just using a non-standard way of checking it. If only PHP was properly installed on my Web server I would write some test scripts and reply with more confidence. :-/

** END PREPEND **

Matthew Leverton said:

You're partially right on the second half, but your conclusion is incorrect. Errors shouldn't occur on the live system, but if they do...

That's what the ::) was for. Geeez, a week of [semi-]emoticon freeness and people stop interpretting them.

There are obviously gonna be errors that slip through our VIGOROUS testing processes. However, more often than not they'll be logical errors anyway and an E_NOTICE in the log probably won't point you to those.

In any case, my argument is at a loss because I agree it's better to follow good practice, which in this case would have to be using isset(). I just find it such an ugly construct. I prefer compiler errors when a variable isn't declared. You know?

Maybe if there was a block of code near the top that checked for isset()s and handled missing variables right away. At least then it would group them together... Whatever. As I've said in other threads, I'm not a fan of Web development as it is today.

Thomas Fjellstrom
Quote:

Purposely writing code that triggers E_NOTICE is simply bad practice.

Oh man did I learn that with perl. Perl lets you do things in almost any way imaginable. More complex scripts can get down right confusing, even for a perl maniac, and without "use strict" strict type checking isn't enabled and all sorts of very "interesting" things are possible, like mixing undefined stuff, all types of symbol references that should almost never happen, and things along those lines.

Its the same reason I use -W -Wall with GCC, and make sure all warnings are gone. I don't need them getting in the way of finding an actual problem.

Theres a reason warnings exist, to tell you you're doing something WRONG. It may not be a fatal error by default, but its still an error, wether you like it or not.

Quote:

I just find it such an ugly construct.

# perl:
if(!defined $var) { ... }
... if !defined $var;

Which is worse do you think?

bamccaig
Thomas Fjellstrom said:

Which is worse do you think?

I'd say they're about the same, but I might actually prefer the defined/!defined syntax. Maybe not. Scripting languages are just evil to begin with. :P

** APPEND **

I can honestly say that in my little PHP writing that I've done I've never relied on a log to tell me where my errors are. I plan my script and test it extensively to be sure it's working as I intended.

What are some examples of hard to notice logic errors that will trigger E_NOTICEs?

BAF
Quote:

I'm not assuming that the variable is set. I'm just using a non-standard way of checking it. If only PHP was properly installed on my Web server I would write some test scripts and reply with more confidence. :-/

So you're telling me that I can do the following in C++ to see if a variable exists:

if(myMagicBitmap)
{
    oh it exists!
}

I think not. You ARE assuming it exists. You explicitly reference it.

Matthew Leverton
Quote:

What are some examples of hard to notice logic errors that will trigger E_NOTICEs?

Typos, logic that prevents a variable from being defined, unexpected index values...

It gets more useful as the project becomes more complex. For simple one-off scripts, it's not that big of a deal. But when you're creating an entire framework/library of code, then it's very useful. (Especially when you forget how you did things...)

bamccaig
BAF said:

So you're telling me that I can do the following in C++ to see if a variable exists...

PHP is in no way C++! Besides, the compiler will tell you if a variable doesn't 'exist' in C++ so, to my knowledge, you shouldn't need to check if one does exist...

BAF, have you even programmed a script in PHP!?

Matthew Leverton said:

Typos, logic that prevents a variable from being defined, unexpected index values...

If you misspell a variable you should quickly see that the intended action isn't happening correctly (during testing) and can use print() statements to trace the execution path.

In terms of logic that prevents a variable from being defined, this can be almost eliminated by declaring your variables at the top of your script, functions, and methods. Which is also a best practice...

???

Again, I guess I agree that you should use isset(), but I still don't like it.

BAF
Quote:

BAF, have you even programmed a script in PHP!?

Resisting... urge...... to be..... smartass...........

I have done a LOT of PHP work. Once upon a (short) time I was pretty naive like you. Then I learned the importance of writing clean code.

Quote:

If you misspell a variable you should quickly see that the intended action isn't happening correctly (during testing) and can use print() statements to trace the execution path.

In terms of logic that prevents a variable from being defined, this can be almost eliminated by declaring your variables at the top of your script, functions, and methods. Which is also a best practice...

Again, I guess I agree that you should use isset(), but I still don't like it.

You may not notice a variable issue like that if it's in an obscure not-well-used code path. The notices really do help save a lot of time. IF you ever start writing important code, you will (I hope..) learn the importance of clean code and the easy way of debugging. You don't need to predefine all your variables at the top, but you definately shouldn't assume stuff like post variables exist. That is just foolish. Also, isset() makes your code more readable.

bamccaig
BAF said:

You don't need to predefine all your variables at the top, but you definately shouldn't assume stuff like post variables exist.

You don't need to, but you should. And I never assumed it was set. Scripting langauges like PHP are funny in that if the variable doesn't exist it will evaluate it as false and therefore in a boolean condition can be treated like a flag. If it was set it would evaluate to true. If it's not set (doesn't exist) is will evaluate to false, similar to null.

I've seen isset() code and I say it's less readable. It all depends. There may be circumstances where my way won't work, but in the even of checking form fields that cannot be zero or empty it works fine. To make it more readable you could easy create a hidden form field to check instead of the button:

1...etc
2 
3<?php
4 if($_POST['hidSubmitted'])
5 {
6 // Form was submitted...
7 }
8?>
9 
10...etc...
11 
12 <form ...>
13 
14...etc...
15 
16 <input type="hidden" name="hidSubmitted" id="hidSubmitted" value="true" />
17 
18...etc...
19 
20 </form>
21 
22etc...

I do write clean code. I'm more obsessive about it than most. It all depends on what you call clean.

Thread #590788. Printed from Allegro.cc