How not to use a variable



  • I found this golden snippet of code in a php BBcode parser's http update function:

            ob_start();
            while (!feof($f)) {
                echo fgets($f);
            }
            $infoTransferred = ob_get_contents();
            ob_end_clean();

    I like to defend php as a sane language, but when people keep doing things like this, it is getting harder... 



  • That's a pretty creative way of ignoring file_get_contents(), but I don't see how it reflects on PHP itself.

     

    Going by that logic, PHP would be the most sane web language of them all, since it appears on this website the least (despite being the most popular language used for web development).



  • @Pap said:

    That's a pretty creative way of ignoring file_get_contents(), but I don't see how it reflects on PHP itself.

     

    Going by that logic, PHP would be the most sane web language of them all, since it appears on this website the least (despite being the most popular language used for web development).

    Probably just someone reinventing the wheel, yet again. Or defining coding 'leetness by the KLOC metric. If they wanted to maximizing lines of code, but still remain relatively efficient, they should have used fread() instead of fgets(), and at least eliminate the overhead of having the parse the data stream for line endings (if any). Not to mention the overhead of the buffering and copying from the buffer at the end.

    'course, ob_get_contents() could use copy-on-write, in which case it's just a pointer, but who knows... I might have to code in PHP for a living, but I'm not going to venture into its guts to find out just how much my livelihood depends on duct-tape and bandaids. 



  • @henke37 said:

    I like to defend php as a sane language
    Good luck with that.



  • I think they do it like that in case file_get_contents() changes in the future or in case a new method is added to PHP that makes more sense to use (or a method they are using gets deprecated).  Instead of going through every file and changing file_get_contents($filename) to file_get_contents2($filename) they can change the functionality of ob_get_contents().

    That's how OSCommerce handles functions too, and that's the only reason I can think of to approach it like that.

    That being said, I don't think that's the main WTF is it? 



  • Did you leave out your sarcasm tags? Comparing something to OSCommerce and therefore justifying it is like defending someone's actions by saying "Well, Hitler did it, so I guess it's ok".

     

    PHP rarely makes such changes to functions. It's clear to me that the coder did not know about file_get_contents().  Even if the reason you mention was in fact the reason, then the appropriate code would look like:

     

    $blah = my_file_get_contents($f);

    function my_file_get_contents($file) { return file_get_contents($file); }

    Where the function goes in some include file. Should file_get_contents() ever change, then you only need to make a change to that one piece of code and you entire application is now safe.

     



  • @Pap said:

    Did you leave out your sarcasm tags? Comparing something to OSCommerce and therefore justifying it is like defending someone's actions by saying "Well, Hitler did it, so I guess it's ok".

     

    Oh, sigged in a [i]heartbeat[/i].


  • Not necessarily. IIRC, file_get_contents only works like that if the other server has url_fopen set to 'true'. Then again, that would go for fread also, so it's prolly a double WTF. But maybe it's a left-over from PHP3 or whatever.

    The real WTF tho is that they could've just used $foo = ob_get_clean(); and be done with it.
     



  • BTW, the language supplies a number of good techniques for this kind of thing (CURL, most notably) so I don't see how any programmer's stupidity should reflect on the language as a whole if the programmer is quite obviously at fault. PHP has its quirks and bugs, but as web programming languages go it's pretty versatile - I've definitely seen a lot worse.



  • @Ceko said:

    I think they do it like that in case file_get_contents() changes in the future or in case a new method is added to PHP that makes more sense to use (or a method they are using gets deprecated).  Instead of going through every file and changing file_get_contents($filename) to file_get_contents2($filename) they can change the functionality of ob_get_contents().

    That's how OSCommerce handles functions too, and that's the only reason I can think of to approach it like that.

    That being said, I don't think that's the main WTF is it? 

     

    Addendum to my above post:  I just now noticed that you don't seem to realize that ob_get_contents() is actually a standard PHP function, not a user-created function.



  • I love bashing PHP for being a completely insane language, and people like this make it so easy :)

    I don't actually know what built-in function he's reinventing/ignoring, since i haven't read and memorized the PHP library documentation, as I'm not into masochism...
     



  • @Pap said:

    @Ceko said:

    I think they do it like that in case file_get_contents() changes in the future or in case a new method is added to PHP that makes more sense to use (or a method they are using gets deprecated).  Instead of going through every file and changing file_get_contents($filename) to file_get_contents2($filename) they can change the functionality of ob_get_contents().

    That's how OSCommerce handles functions too, and that's the only reason I can think of to approach it like that.

    That being said, I don't think that's the main WTF is it? 

     

    Addendum to my above post:  I just now noticed that you don't seem to realize that ob_get_contents() is actually a standard PHP function, not a user-created function.

     

    Yes, I didn't know that ob_get_contents() was a PHP function, so nevermind my post.  Also, I'm not arguing that you should emulate OSCommerce standards, just trying to explain why someone would code like that if ob_get_contents() was a user-created function.



  • Perhaps the writer wanted to avoid putting the entire contents of the file into a variable at once time? That could be ugly with a 1GB file.



  • @Toger said:

    Perhaps the writer wanted to avoid putting the entire contents of the file into a variable at once time? That could be ugly with a 1GB file.

    Actually, that's exactly what they're doing. By default while running under a webserver, any output in PHP (print, echo, certain function calls, etc...) will have that output sent to the remote client. Sometimes you don't want that, which is where the ob_*() functions ([O]utput [B]uffer) come into play. In essence, they're slurping up that file one line at a time (assuming the file even has line break characters, it could just be a few terabytes of 0xFF), echoing it out into a buffer, then once the file's been slurped, spitting the buffer contents out into a variable.

    Which is the whole point of the OP. That chunk of code could've been replaced with:

        $infoTransferred = file_get_contents('/path/to/file');

    and gotten the exact same results. Either way, if the file was huge, they'd exceed the memory limits and cause the script to abort. On top of all this, they're now adding the overhead of having to maintain the buffer, append to it, and empty it aftewards.

    OSCommerce is a very LARGE steaming pile of crap - I had to install it once for a client, and hurriedly uninstalled after about 10 minutes of playing with it. For one, it REQUIRES that you have register_globals turned on, which means the coders are a bunch of lazy bastards who can't be bothered to write an even marginally secure system. It's not surprising that whoever banged out that chunk wouldn't know about file_get_contents, but it is surprising they'd know about the output buffer system. To be fair, the OSC forums had a user patch to remove the need for register_globals, but still - the latest/greatest versions still require it. Thanks, but I prefer to keep my servers somewhat less exploitable than that.

     

    Remember the old line about C being powerful enough to let you shoot yourself in the foot, and C++ being powerful enough to let you blow off your leg? PHP is powerful and silly enough to let you take out the entire neighborhood. 



  • I like the fact that if there's something else in the buffer (as in the case if automatic buffering is on at the server), not only you lose that output, but you also get it in your variable, prepended to the file. Brillant.



  • @Sunstorm said:

    I like the fact that if there's something else in the buffer (as in the case if automatic buffering is on at the server), not only you lose that output, but you also get it in your variable, prepended to the file. Brillant.
    It turns out that's not the case... The ob_start() command initialises a new output buffer, and ob_get_contents() only returns the contents of the innermost buffer... At least, I think that's what this fragment is telling me:

     

    bash$ cat buffer.php
    <font color="magenta"><?php</font>
       <font color="blue">ob_start</font><font color="magenta">()</font>;
       <font color="blue">print</font> "<font color="red">Test</font><font color="magenta">\n</font>";
       <font color="blue">ob_start</font><font color="magenta">()</font>;
       <font color="blue">print</font> "<font color="red">Stuff</font><font color="magenta">\n</font>";
       <font color="lime">$</font><font color="blue">stuff</font> <font color="lime">=</font> <font color="blue">ob_get_contents</font><font color="magenta">()</font>;
       <font color="blue">ob_end_clean</font><font color="magenta">()</font>;
       <font color="blue">print</font> "<font color="red">got: </font>" <font color="lime">.</font> <font color="lime">$</font><font color="blue">stuff</font>;
       <font color="blue">ob_end_flush</font><font color="magenta">()</font>;
    <font color="magenta">?></font>
    bash$ php buffer.php
    Test
    got: Stuff
    bash$
    


  • Well, that's interesting. I didn't know that.

    Opens up a different question though. How much more efficient would be using the output buffer when compared to simple string concatenation? It would be insane if it actually worked better...
     


Log in to reply