Please stop using php's @ sign error control operator

Hello,

I've long planned to switch to zenphoto (from Menalto Gallery) for many reasons revolving mostly around your philosophy.

Then I tried it today. And spent most of my day trying to figure out why the setup was totally failing, or partially working then totally failing. The basic symptom was that depending on the permissions of the files in the zenphoto distribution on my server (which I host entirely myself, so I have full control over apache and php), the site would either fail to setup because it couldn't read/write things, or would just return a 500 error.

I frequently found google searches that referenced posts on this forum, with other people having the same problem. Mostly you told them "it's your fault, or your hosting provider's fault, go complain to them". I am my own hosting provider, and I run a sane setup, and I had no idea what to do.

The biggest problem was that the 500 errors were not logged anywhere - not in my site-specific apache logs, not in my global apache logs, not in my global php log. I fiddled with apache settings, log levels, log locations, php settings, filesystem permissions, and nothing worked.

I finally narrowed it down to a single file - zp-data/zenphoto.cfg. Depending on who owned that file (my user or my apache user) and what the specific permissions were on it (660 or anything else), I'd either get the 500 error or I'd get the setup page, but it would complain that it couldn't read that file. Still no error logged anywhere that helped.

So I started digging through the code, putting print "GOT HERE"; in, and moving it around until I could narrow down where the problem was happening.

Turns out it was happening because zenphoto.cfg specified the database as "mysqli" (which I'd never heard of, but google suggested that it was the best option, so I left it). So the setup was calling "mysql_connect" which was calling "mysqli_connect" which was failing.

Because I don't have the mysqli extension installed on my system. I'm running on netbsd, using pkgsrc, and it isn't installed by default with php, and I'd never needed it before now.

BUT YOU HAD AN @-SIGN IN FRONT OF THE mysqli_connect CALL, SO IT NEVER REPORTED THE ERROR ANYWHERE!!!

Yeah, it's pretty damn angering that I spent hours trying to understand why this wasn't logging any error only to discover that you were using a hare-brained 'feature' of php that seems to have the only purpose of making production issues harder to debug. And you use it all over the place!

So next time someone asks about 500 errors, please apologize to them instead for how extremely difficult you've made it for them to debug those errors, rather than crankily telling them to go talk to their server admins. (I will concede that this was a server-admin-level issue - but you've made it impossible for the admins to understand what is going wrong!)

I haven't quite given up on zenphoto; I've had my heart set on it for years. But this is seriously questionable coding practice, and it makes me question whether I'm really going to have a better experience here.

Thanks for listening,
Nathan

Comments

  • acrylian Administrator, Developer
    Sorry for your trouble. I cannot answer why there is an @ before that call nor where that is in the moment. My colleague would surely be later.

    It is always easier if we can reproduce things to help. The best is you open a ticket for this on the bugtracker with all line number and what you find useful so it does not get lost to investigate later.

    General: mysqli is actually a default server database engine extension that is or should be part of a standard php installs nowadays and it or PDO is the recommended one to use. The mysql extension will be noted as deprecated from php 5.5 on. (http://php.net/manual/en/intro.mysql.php). Setup should note what of those three extensions is available.
  • The biggest problem was that the 500 errors were not logged anywhere
    Well, this certainly is not a Zenphoto issue--if you get a 500 error Zenphoto never even gets loaded.
    BUT YOU HAD AN @-SIGN IN FRONT OF THE mysqli_connect CALL, SO IT NEVER REPORTED THE ERROR ANYWHERE!!!
    And if we did not, you would not be able to run setup at all.

    If you did not have the `MySQLi` PHP module enabled Zenphoto would not use that library. If you have the PHP module but not the underlying support then you certainly cannot blame Zenphoto. If someone manually edited the configureation file to use that module it is again not Zenphoto's fault.

    I would suggest you get off your high horse and appologize to us for your tirade.
    Because I don't have the mysqli extension installed on my system. I'm running on netbsd, using pkgsrc, and it isn't installed by default with php, and I'd never needed it before now.
    Since apparently you set thing up yourself, you should at least do it correctly.
  • (somewhat out of order, for clarity)
    I would suggest you get off your high horse and appologize to us for your tirade.
    Yes, you are right; I had no business yelling. You are providing software for free, and I'm complaining that it isn't what I wanted, and blaming you for that. I apologize.
    Well, this certainly is not a Zenphoto issue--if you get a 500 error Zenphoto never even gets loaded.
    Not so. The 500 error basically just indicates "php crashed". That can happen because of a parse error - before Zenphoto is loaded - or because of an unchecked call to a function that doesn't exist (as in my case) well into Zenphoto's execution. It was exactly that thing that was happening to me, and that's why I was able to put "GOT HERE" messages in the code to figure out where it was breaking - as long as there was output, apache was still returning it to the browser, before the error. Once I moved the "GOT HERE" to after the offending line, the browser just saw the 500 error.

    It's easy to demonstrate for yourself:

    `
    <?php
    print "This line will always print, but if you comment it out...";
    @youll_get_a_500_error_because_this_function_doesnt_exist_but_it_wont_be_logged();
    print "Either way, you'll never get here.";
    ?>
    `
    And if we did not, you would not be able to run setup at all.
    No so; php provides one or more ways to guard against any possible error; the @-sign is just a programmer convenience so that you don't have to write the code to guard against the error you were worried about. The problem is that it also guards against all other errors, even ones that prevent further script execution (like a function that isn't available), even if you weren't expecting that - and it does it in a way where the error is never logged. So basically, every bug you have, and every local configuration issue your users have, in a line of code with an @-sign, becomes a nightmare to debug in production.
    If you did not have the MySQLi PHP module enabled Zenphoto would not use that library. If you have the PHP module but not the underlying support then you certainly cannot blame Zenphoto. If someone manually edited the configureation file to use that module it is again not Zenphoto's fault.
    Not so. Zenphoto does not check whether mysqli is available on the machine; it just blindly trusts the config file and tries to call mysqli_connect which doesn't exist so it throws an error. The @-sign makes php eat all error logging about that error, but the script dies at that point anyway.

    Nobody manually edited the configuration file to use that module (it's just me here); mysqli is the default choice in the default config file. I saw it and didn't understand it but assumed that I see an error message about it if it was wrong. Instead it caused a php crash with no error logged. That's the worst possible behavior on Zenphoto's part.
    Since apparently you set thing up yourself, you should at least do it correctly.
    I had a perfectly-reasonable configuration of php (without mysqli) - the PHP documentation is explicit that mysqli is optional, and even that it might have to be explicitly added if you want it. My reasonable configuration combined with your (unsafe) assumption that mysqli would be present to cause a script failure, and the @-sign caused the failure to be totally unlogged. If that @-sign hadn't been there, I would have had a perfectly-understandable log message that would have led me to configure mysqli, easily.

    You use that @-sign liberally all over the code, and you have frequent complaints here on the forum about 500 errors with no explanation in the logs. It seems likely that this isn't the only case where the @-sign is a problem. Thus, my original request that you stop using the @-sign.
  • acrylian Administrator, Developer
    Apology accepted. We appreciate any comment to make Zenphoto better. I don't remember all forum posts about 500 internal server errors but in my memory most of them are because of permissions, missing wrong/htaccess or accidentally corrupted files on upload. But of course my memory might be wrong.

    We test Zenphoto on standard shared hostings and local MAMP/WAMP servers and never had this issue. Being able to encounter or reproduce it is of course the most important to do anything.

    My colleague later will surely further respond as he is the actual coder of the setup scripts.

    Quick update: He already added some setup improvements to the support build. Please try it.
  • While Zenphoto may cause a crash, there is still no means for it to log the error as PHP is aborted on a 500 error.

    It is not the @ sign that is the issue anyway. That is a normal and accepted means to supress error messages that are expected. In the case of the database connection, that will occur if the credentials are not correct. Not supressing the error means that the user has no means to correct (or supply) the credentials.

    There are similar reasons for the other uses of the @ sign. It may be that other expected modules get left out of PHP configurations. That is not normal and not done by the professional hosting sites. If someone wishes to configure his PHP in a custom way he is expected to be able to deal with the consequences. We certainly cannot test all the possible PHP configuration permutations and may well miss the fact that a particular function might be in a commonly included module but omitted in a particular case for some unknown reason.

    As to your "perfectly reasonable PHP configuration" you should note what the PHP documents themselves say:
    Warning
    This extension is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQL extension should be used. See also MySQL: choosing an API guide and related FAQ for more information. Alternatives to this function include:
    ? mysqli_connect()
    ? PDO:GDN__construct()

    Of course the configuration is possible and therefore we should properly run under it. That is now the case. We certainly could have got to this point sooner if your posting was constructive rather than distructive.
  • While Zenphoto may cause a crash, there is still no means for it to log the error as PHP is aborted on a 500 error.
    Not so; if you remove the @-sign from the example I gave above, the error will be logged in the php logs (if you have them configured). The user still sees a 500 error.
    It is not the @ sign that is the issue anyway. That is a normal and accepted means to supress error messages that are expected. In the case of the database connection, that will occur if the credentials are not correct.
    That's exactly my point - you are using the @-sign to suppress the error you expect, but you are also suppressing all other errors from that line of code, which is why it's so dangerous. If there is an error that you weren't expecting (and you can't claim to never have those) then it won't be handled, reported, or logged. That's the worst possible way to handle an unexpected error.
    Not supressing the error means that the user has no means to correct (or supply) the credentials.
    No so; there are multiple other ways to deal with the error - try/catch, set_exception_handler(), and set_error_handler(). (I believe try/catch is perfectly suited to this situation, but I haven't tested it.) All of them will allow you to deal with the issue and/or will log the issue.
    There are similar reasons for the other uses of the @ sign. It may be that other expected modules get left out of PHP configurations. That is not normal and not done by the professional hosting sites. If someone wishes to configure his PHP in a custom way he is expected to be able to deal with the consequences. We certainly cannot test all the possible PHP configuration permutations and may well miss the fact that a particular function might be in a commonly included module but omitted in a particular case for some unknown reason.

    That's exactly why you shouldn't use the @-sign: you can't test all the possible configurations, and the @-sign makes it nearly-impossible to identify issues that result from those configuration differences. Is your argument that people should only use this software if they're running on one of the standard hosting sites?
    As to your "perfectly reasonable PHP configuration" you should note what the PHP documents themselves say: [snip]
    I'm using PHP 5.3, which is described as supported by Zenphoto. (I tried upgrading to 5.4, but that cascades into other dependencies that I'm not ready to upgrade yet.) At the time of 5.3, it was perfectly reasonable to run without mysqli. (And note that 5.5 isn't officially released, yet!)
    Of course the configuration is possible and therefore we should properly run under it. That is now the case.
    Great! Thank you very much.
    We certainly could have got to this point sooner if your posting was constructive rather than distructive.
    Yes, probably, and I'm sincerely sorry about that. I do still think that the larger issue is important, though - the @-signs are dangerous, and they're going to cause major headaches for other people in the future. (And they were probably the source of many headaches in the past.) They make the software less debuggable in the field, and I suggest you stop using them, and make an effort to remove them where they already exist.
  • That's exactly my point - you are using the @-sign to suppress the error you expect, but you are also suppressing all other errors from that line of code, which is why it's so dangerous. If there is an error that you weren't expecting (and you can't claim to never have those) then it won't be handled, reported, or logged. That's the worst possible way to handle an unexpected error.
    So we are here between the devil and the deep blue sea. We must be able to supress "expected" errors or Zenphoto will not work. But if there are "unexpected" errors they should not be supressed. Unfortunately, there is only one option, supress all errors or not. Maybe that is a PHP weakness, but it is one we have to live with.

    Try/catch does not allow one to continue from these kinds of errors. Exception handlers might work if one knew all the error mappings. Unfortunately that is not documented as well.

    Certainly our experience is NOT what you indicate. The 500 errors reported on this forum are typically from filesystem security issues and from hacks like Sushin which do exactly what you complain of--force an error but not report it.
    'm using PHP 5.3, which is described as supported by Zenphoto. (I tried upgrading to 5.4, but that cascades into other dependencies that I'm not ready to upgrade yet.) At the time of 5.3, it was perfectly reasonable to run without mysqli. (And note that 5.5 isn't officially released, yet!)
    Of course MySQL is still available in your PHP 5.3, but that is actually not the point. Since it will be removed (and is not recommended in the first place) all reasonable software will move off using MySQL to using MySQLi. But you will prevent those from running on your configuration since you CHOOSE to run an obsolete configuration.

    I will again repeat what I have said. There are close to infinate permutations of what can be configured with PHP and servers. We test with only a small subset of these. If you choose to deviate you may have problems. Then you will need to figure out why. We will normally help, but probably not if provoked.
  • I've also long intended to switch to Zenphoto, and this thread gives me a strange feeling. Developing software products is about balancing competing priorities and making calculated tradeoffs, so I understand the desire for Zenphoto to run smoothly in popular configurations and not warn (or die) unnecessarily. But it sounds like those nice properties have come at the cost of considerably reduced robustness. Some known simple problems have been rendered difficult to trace and debug. Worse, unknown problems have been made hard to find too. Whether you're evaluating Zenphoto or relying on it in production, it's been arranged that the inevitable software surprises will bite you especially hard.

    It's not reasonable to claim that the Zenphoto developers should test all possible configurations, or that it's Zenphoto's "fault" if its runtime dependencies aren't being met. It is entirely reasonable to claim that the Zenphoto code should fail clearly and cleanly when some aspect of the configuration doesn't meet its requirements, as well as when some unexpected error occurs.

    PHP isn't my strongest language, and I don't know anything about your userbase or support load, but it sounds to me like the tradeoff you've chosen must be hurting you and your community. Is there really no better way to accomplish your goals for your product?
  • I really think it would hurt our community more gravely if we took any other apporach. We simply do not have the resources to test combinitorilaly.

    PHP does not fail gracefully when a function is used and does not exits if we are going to suppress the expected error messages. It should do as advertised and return a NULL response. Instead it fails in a means that is not possible to trap.

    So What you seem to be asking us to do is place a test on each and every function we use to see if it is acutally present as expected. We would then have to change the name of our product from "zen" implying light weight to "Pudgy".

    Not going to happen. If you cannot live with this then the product is not for you.
  • I don't think "runtime behavior that's difficult to predict" or "unpredictable behavior that's difficult to debug" are tolerable properties of software systems -- particularly not both at the same time! -- with the possible exception of systems designed solely for didactic purposes. (Even those have a way of escaping into the real world and forcibly didacting innocent people.)

    But it's your software system. You get to choose the properties you desire it to have, and you get to choose the tradeoffs you think best engender those properties. I genuinely appreciate your willingness to direct me elsewhere rather than compromise your product values. I just think you've constructed a false dichotomy. For instance, instead of testing the existence of every function you call at every invocation (which I agree would be "Pudgy"), do it in standalone test code. Then you can instruct users to run the tests before installation and also later on, if the software ever starts misbehaving. You'd have to make sure your tests and your code stay in sync over time, of course. I can think of some ways to automate that, and were it my code, that's a development cost I'd gladly pay in exchange for the "Zen" of quickly and reliably characterizing problems in the field. But it's your code and your tradeoff.

    Finally, it's weird and disconcerting that when people say "nobody is asking you to test combinatorially", you seem to hear "we're asking you to test combinatorially". I appreciate your taking the time to reply to me. I would have appreciated it more if I felt I'd been heard and understood. But then, whether to make the effort to listen to your users (or potential users) is another tradeoff that's yours to choose.

    I'm glad to have had this discussion. Thank you, and best of luck with Zenphoto.
  • Take up your concerns with the PHP people then, it is their software which makes what you want impractical.
    For instance, instead of testing the existence of every function you call at every invocation (which I agree would be "Pudgy"), do it in standalone test code. Then you can instruct users to run the tests before installation and also later on, if the software ever starts misbehaving.

    Your are kidding, right. Either that or you are terribly naieve. Do you know what your entire vocabulary is? Do you "test" to see if everyone can understand these words before you speak? No, you do not. One makes reasonable assumptions about the world out there and goes on them. Anything else would result in paralysis by analysis.
    I can think of some ways to automate that, and were it my code, that's a development cost I'd gladly pay in exchange for the "Zen" of quickly and reliably characterizing problems in the field. But it's your code and your tradeoff.
    I take it you are volunteering to do this? We would be happy to have your addition.
Sign In or Register to comment.