Join David Powers for an in-depth discussion in this video Changes to calculations with strings, part of PHP Tips, Tricks, and Techniques.
- [David] Hi, I'm David Powers and welcome to this week's edition of PHP Tips, Tricks and Techniques, designed to help you become a smarter, more productive PHP developer. This week I'm responding to a query, that came from a member about my course, PHP: Uploading Files Securely, the code had worked perfectly for several years, but suddenly it generated an error about a non well formed numeric value, so what did that mean? Calculating with numeric strings has always been a rather cool feature of PHP, you can use a string like this, that begins with a number, but has trailing, non-numeric characters in a calculation, PHP strips off the trailing text and type juggling converts it to a number, but since PHP 7.1, using a numeric string, that has trailing non-numeric characters in a calculation generates an error notice, yeah, big deal, you might be thinking, multiplying 76 trombones by two, well, that's a neat party trick, but who in their right mind would ever need to perform a calculation like that? Well, in my Uploading Files course, I did, so let's switch to my editing program.
This file shows what I was doing, incidentally there's a copy in the download files for this video, I needed to find out the maximum size of files, that can be uploaded at a time, using the post method, so this script gets the value of post_max_size from the service configuration and there on the following line, we're displaying it, so if I run this script by loading this file into a browser, on my testing server, it displays 8M, in other words eight megabytes, if you try this yourself, the value will depend on your service configuration, the value can be changed by the server administrator, so g indicates gigabytes and k indicates kilobytes, but instead of using this shorthand, some servers express the value as the number of bytes and for my code to work on any server, I needed to convert the value of post_max_size to bytes and I did that using this function, convert ToBytes, it takes a single argument, the value that you want to convert.
On line eight, we get the last character from the value and convert it to lower case, then the conditional statement that begins on line nine goes through this array, comparing the last character, making sure that it's either g, m or k, if it is, it then passes it to this switch statement, normally each case in a switch statement ends with break, but here I'm not using break, so if the last character is g, val will get multiplied by 1024 three times, if it's m, it will be multiplied twice and if it's k, it will be multiplied just once and the function ends by returning val and if the last character wasn't g, m or k, we assume that it was originally in bytes and if it's in bytes, we don't convert it at all.
I originally created this code in 2014 and it's always worked perfectly, so let's use it to convert post_max_size on my server to bytes and display the result, I'm going to comment out line three, then we'll create a new variable called maxbytes, then we'll use the convert ToBytes function, passing it the value of max to convert it and then display maxbytes, so if we save that and refresh the browser, on my server I get this notice, a non well formed numeric value encountered in this file on line 18 and then it gives me the result, I'm getting this error notice, because my server is running PHP 7.1 with the level of error reporting turned up to the highest level, if you are using an older version of PHP, or if you've turned off notices, you'll just see the result, although the value will depend on your own configuration, notices are the lowest level of errors in PHP and a lot of developers ignore them, but I believe you should always eliminate errors, even if the code still works as expected, notices indicate a potential problem, that could come back to bite you unexpectedly.
Now our first idea was to strip off the final character of the value, before using it in the calculation, that would work in this script, but it's not a very flexible solution, here I know that I need to remove just one character, but what about a situation, where you don't know how many trailing non numeric characters there are? My next idea was to use a regular expression, but that raised a lot of questions, if we're just dealing with integers, that would be simple, but what if there's a decimal fraction? Would the fraction have a leading zero, if it was smaller than one? What about a leading positive or negative sign? Not to mention whether the regular expression would need to handle numbers, using scientific notation.
While not impossible, using a regular expression to extract the number at the beginning of the string was going to be too complicated, so that idea went out of the window and suddenly the answer came to me and it was so simple, PHP's type juggling uses implicit casting to convert strings that begin with a number to a numeric data type, so instead of relying on implicit casting, why not use explicit casting? So let's get back to the editing program.
So if we know that our value ends in g, m or k, we need to cast it to a numeric value, so inside that conditional statement, add in another line, we'll reassign it to val and then we need to use the casting operator to convert from one data type to another, the casting operator in PHP is wrapped in a pair of parentheses and if you know that the string is only going to contain an integer, you can use int, but to cover both integers and numbers with decimal fractions, we can use float and then we just have the value, that we are converting, so if we save that and then refresh the browser, that error notice goes away and we get the correct result, so there you have it, a really simple solution to eliminating the error notice, that you get, when using a string that begins with a number, but has trailing non numeric characters in a calculation in PHP 7.1 or later, use the int or float casting operator to convert the string to the required numeric type, if in doubt, use float, because it works with both integers and values, that have a decimal fraction.
Well, that's it for this week's PHP Tips, Tricks and Techniques, thanks for watching, I hope you can join me next time.
Note: The exercise files are free to all members. The code is commented to enhance your learning, but you will need database connectivity for some files to run as intended.