Quantcast
Channel: EdgeRouter topics
Viewing all articles
Browse latest Browse all 20028

PHP numeric casting failures

$
0
0

I was interested in monitoring bandwidth usage on my ER Lite 1.8.5 and found My bandwidth monitoring solution..... It discusses vnstat available via apt-get and some php code called vnstat PHP frontend.

 

vnstat was easy to install and get working. The php code was anything but easy. After installation, viewing a page in the browser returned 500 - Internal Server Error. Looking in /var/log/lighttpd/error.log showed:

 

2016-07-04 18:00:40: (mod_fastcgi.c.2562) unexpected end-of-file (perhaps the fastcgi process died): pid: 1976 socket: unix:/var/run/php5/php.socket-0 
2016-07-04 18:00:40: (mod_fastcgi.c.3346) response not received, request sent: 991 on socket: unix:/var/run/php5/php.socket-0 for /stat/index.php?, closing connection

I am not a PHP programmer so I googled "fastcgi process died" and variants where most comments were of the sort: "did you check if the process died" which was not very helpful. And checking the pid in the error message showed that /usr/bin/php-cgi was still running at that pid as well as four others. It turns out that "perhaps" is largely nonsense. What it really means is that something blew up in the php processing of the particular page and processing of that page terminated. And btw, the web GUI for the router still worked fine.

 

It took me quite awhile to figure out how to debug this (using syslog for messages) but I finally tracked it down to a formatting routine which was trying to output string representations of an integer number of kilobytes as either KB, MB, GB, or TB. To do so it divided the string integer by integer powers of 1024 and then using sprintf("%0.2f". $val). Most of the divisions by powers of 1024 yielded results that were of type double and this was fine for the sprintf. But in the case the value was less than 1024, it divided by 1 and this yielded a result of type integer on which the sprintf failed causing the error. Since I had just installed vnstat, there wasn't much data collected so many values were still sub-MB size. And any such value on a page would blow it out.

 

I tried to fix this by taking floatval($val) to convert it to a double but it turns out that floatval of an int value also blows out. What?! So does (double)$val and (float)$val. I finally got it to work by doing 0.0 + $val. Doing this got most of the pages to start working.

 

But the graphs which are embedded objects in the pages were not appearing. They were also blowing out but being embedded they didn't take the entire page out. Debugging that I found many instances of (int) casts of doubles that were failing as well as some more sprintfs with %F blowing up on int values. I used my 0.0 + trick to convert to doubles and removed all (int) casts in the code as I could not find a way to successfully convert from double to int and voila, the graphs appeared.

 

I created a test php page called fail.php with contents included below. The page loads as is but if any of the lines which are commented out and marked as 500 - Internal Server Error are uncommented, the page will fail and return the error even though all of these conversions should succeed except maybe the last sprintf where I would think an int would auto-convert for a %f format.

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><title>PHP Failure</title></head><body><?php
          $x = (int)1;                // Page SUCCEEDED!
//        $x = (int)1.2;              // 500 - Internal Server Error
          $x = intval(1);             // Page SUCCEEDED!
//        $x = intval(1.2);           // 500 - Internal Server Error
          $x = intval("1.2");         // Page SUCCEEDED!
//        $x = (double)1.2;           // 500 - Internal Server Error
//        $x = (float)1.2;            // 500 - Internal Server Error
//        $x = (double)1;             // 500 - Internal Server Error
//        $x = floatval(1);           // 500 - Internal Server Error
          $x = floatval(1.2);         // Page SUCCEEDED!
//        $x = floatval("1.2");       // 500 - Internal Server Error
          $x = sprintf("%0.2f", 1.2); // Page SUCCEEDED!
//        $x = sprintf("%0.2f", 12);  // 500 - Internal Server Error; should this work? IDK
    ?>
Page SUCCEEDED!</body></html>

Another thing that made this hard was the page was being cached and no matter how I tried to turn page cacheing off, I failed. So when I modifed the php code, trying to reload the page might not reflect the changed code for awhile. I ended up putting a syslog at the top of the page and changing its output so that logging would show whether the new changed code was taking hold.

 

Finally, I am doing this an an ER Lite which has a mips64 processor. Yet the int size in php is only 4 bytes or 32 bits rather than 64 bits. Why is this? Was it just compiled for 32 bits? I care because in the bandwidth case, a max 32 bit int (signed) tops out around 2 GB and since the counters in vnstat are of KB's, this tops out around 2TB. I won't use that much in a month but could easily in a year and that would cause problems.

 

So, I wanted to inform the Ubiquity folks about my php experience. I really don't understand why php is so flaky. Maybe they can look into it.


Viewing all articles
Browse latest Browse all 20028

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>