PHP OCI, Oracle, and default number format - php

When I execute a fetch from an Oracle database using PHP OCI, numbers that are less than 1 are shown as .XXXXXX, e.g. .249999. Is there a way to set this to 0.XXXXXX or to any other format, without modifying every query to use to_char() explicitly? (Perhaps through some session parameters?)

Using PHP you can easily add the 0, by converting to float:
$a = '.249999';
echo (float) $a;
Meaning you can convert your number by
$row['number'] = (float) $row['number'];
after fetching it from the DB.

There is no way to do what you're asking globally short of modifying php/oci-extension source code. The reason for this behavior is because oracle oci omits 0s in results and php converts all results from oci to strings without performing any casting depending on column datatype. Even results in SQL*Plus omit 0 by default, and SQL*Plus formatting has to be invoked with set numformat to customize column formatting and prepend 0s.
There is currently no alter session parameter you can set to change this behavior.
Most common way to work around this is to use a wrapper around your queries and check for numeric columns with is_numeric and then format the numeric column values with number_format or sprintf. Hopefully your application already uses a wrapper around stock php oci functions so you can make the change in one location.

If you need to fix decimals numbers in multiple rows, here's a function to solve it.
function fixDecimalNumbers(array $fetchedDataset)
{
//workaround for Oracle driver not returning leading zero on decimal numbers between -1 and 1 -.-
foreach($fetchedDataset as $rownum => $row){
foreach($row as $column => $value) {
if(substr( $value, 0, 2 ) === '-,' && is_numeric(substr( $value, 2, 1 ))){
$row[$column] = '-0' . substr( $value, 1);
error_log($column);
error_log($value);
}
else if(substr( $value, 0, 1 ) === ',' && is_numeric(substr( $value, 1, 1 ))){
$row[$column] = '0' . $value;
}
}
$fetchedDataset[$rownum] = $row;
}
return $fetchedDataset;
}

The simplest option
$a = '.249999';
echo ($a*1);

Related

How to add numeric value to value without adding or subtracting it in php

I would like to post a value to my MySQL database in this format;
01, 02, 03...
011, 012, 013...
0101, 0102, 0103,
etc.
(with a 0 before each value).
If I do it like this "01+1" I (understandable) get the value 2 and not "02".
is there a default php function that let's me set the default amount of characters or is there an other option?
I'm using laravel combined with eloquent and some own functions like so;
$lastSKU = $data->GetData('get', 'products', 'filter')->max('SKU');
$newValue = $lastSKU+1;
Thanks in advance.
It sounds like you won't know how the format will be, if there is always a 0 in front it is easy enough to do
$value = '0'. ( $value + 1 );
PHP will automatically convert it to a number between the brackets and by adding a string to it it will become a string again.
Now if you do not know the the length or the padding in advance but you do need to keep the current padding I would suggest something like
$value = str_pad(($value + 1), strlen($value), '0', STR_PAD_LEFT);
Edit, str_pad is a bit slow these days, sprintf can do the same trick but much faster
$value = sprintf("%'.0" . strlen($value) . "d\n", ($value +1));

Format number as currency

I am (learning) using PHP to select column data from MySQL into an array using this, CONCAT('$',FORMAT(price, '5')) as price and it outputs $1,751.60000 or $10.00230 or $7.23000 which is great.
However, I would like to remove the trailing zeros but still be able to have a minimum of two decimal places
$1,751.60000 = $1,751.60
$10.00230 = $10.0023
$7.23000 = $7.23
I have read a number of similar post regarding number to currency conversion but none doesn't seem to solve my problem as they remove all the trailing zeros.
We will implement this in two way.(Mysql, PHP).
MYSQL:
FORMAT('price', 2 ) This is mysql function. It takes first parameter as value & second parameter is the number of decimal places.
Syntax:
FORMAT( value, Decimal );
Example:
FORMAT('1751.60000', 2 ) => 1751.60 // Output
FORMAT('1751.60000', 3 ) => 1751.600 // Output
PHP:
In PHP we have number_format() function. This is working same as MYSQL.
Syntax:
number_format( value, Decimal );
Example:
number_format('1751.60000', 2 ) => 1751.60 // Output
number_format('1751.60000', 3 ) => 1751.600 // Output
The Best way is to implement at MYSQL.
Note: These both function round up the values.
I will post this code in PHP since it is easier for me.
$price = $row['price']; // the original price
if (number_format($price, 2) == $price) {
echo '$'.number_format($price, 2);
} else {
echo '$'.rtrim(number_format($price, 5),'0');
}
rtrim will remove any trailing character specified. In this case, remove trailing zeros.
Note : I only put this code number_format($price, 5) because of the sample of the question. If you wish to keep all decimal number minus trailing zeros, just using $price is enough.

Mass Variable Decimal Places PHP

I know you can tell a variable to go to a certain number of decimal places using:
string number_format ( float $number [, int $decimals = 3 ] )
However, I cannot find a way of doing this en masse for all numbers. Since I have hundreds of variables, all of which need to have the same number of decimal places (whether it means rounding or extending zeros), I would like to be able to just tell it to automatically perform this command across the board instead of typing in the above command for all variables.
Does this function exist, or am I forced to type it all out the long way? Is there maybe a line in the .ini file that I could change if there is no command?
Thanks in advance.
I'm not storing these numbers in a database - I'm echo-ing them on the screen and sending an email.
(There is an equation going on from user input being generated by an HTML form).
The person receiving the email has asked that all numbers be rounded to the third decimal, whether that means rounding off at the thousandths or extending zeros to the thousandths if it only needed whole numbers, tenths, or hundredths. There are literally hundreds of individual variables, i.e. $number1, $number2, etc.
If you are talking about all numbers applied to string variables in your script you could run this line:
if(is_int($value) || is_float($value)){
$value = number_format ( float $number ,3 );
}
Obviously as you reference strings you can also run a similar query to check if your string is a floating numeric:
$values = get_defined_vars();
foreach ($values as $key=>$value){
if(is_string($value) && (float)$value == (string)$value){
$value = number_format ((float)$value , 3 );
}
/***
Save over the original script variables with the edited ones.
Note double dollar
***/
$$key = $value;
}
unset($values,$value,$key);
You could do with reading that in base-2 (computer storage) floating point numbers are inherently stored inaccurately, read http://floating-point-gui.de/ .
Also, really, why would you need this seemingly needless precision?
But then at what stage do you run this command, at the start of your script when the values are mostly empty? Or at the end when the values are mostly been used and no longer active?
I think my answer answers your question but I think that your question does not actually articulate your issue.
In response to the comment / edited qestion:
Simply rather than using $values = get_defined_vars(); use the values from saving the inputs into an array and doing foreach above through the array.
$values = array(array of numbers);
foreach ($values as &$value){
if(is_string($value) && (float)$value == (string)$value){
$value = number_format ((float)$value , 3 );
}
}
unset($value,$key);
This will update all values in the array to being of the spcified numerical placements.
You can use the decimal extension to achieve this, with a central place to create and format. Something like this:
class Number
{
public static function create($value, $precision = Decimal::DEFAULT_PRECISION): Decimal
{
return new Decimal($value, $precision);
}
public static function format(Decimal $decimal, int $places = 3): string
{
return $decimal->toFixed(3);
}
}

Handling large numbers in PHP

After a couple of minutes i've realize the bug that i was having: the magic 2147483647 number, that upper limit for integer type on PHP/32. I need to manage biggers number in my function:
public function albumExists($name) // e.g. 104112826372452
{
$albums = $this->getAlbums();
// If $name is int, search the key in $albums
if(is_int($name) && ($found = array_key_exists($id = intval($name), $albums)))
return ($found ? $id : false);
// Start looking for $name as string
foreach($album as $id => $a) if ($a->name == $name) return intval($id);
return false; // Found nothing
}
in order to give the ability to search both by id and name. But intval() will always return the upper limit. How can handle quite big numbers like, say, 104112826372452? Ideas?
EDIT: usage example:
$album = $fb->createAlbum('Test Album'); // Will return album id
// The use albumExists to check if id exists
$photo1 = $fb->uploadPhoto('mypic1.png', null, $album);
$photo2 = $fb->uploadPhoto('mypic2.png', null, 'Test Album'); // find or create
If you're converting to an int for sanity purposes (so it appears), perhaps you could just adjust it to evaluate it purely on it's numeric basis instead of int datatype:
if(ctype_digit($name) && ($found = array_key_exists($id = $name, $albums)))
return ($found ? $id : false);
//etc
Actually, should this work too?
if(ctype_digit($name) && ($found = array_key_exists($name, $albums)))
return ($found ? $name: false);
//etc
As workaround you can use the gmp or bcmath functions for that.
It's not quite clear why you insist on casting to PHP integers. Just leave your database numbering as strings, when don't need to calculate with them. Not everything that looks like a number needs to be represented as number.
I guess your real problem is the differentation with is_int(). Just use is_numeric() in its place, which works with arbitrary-length numeric strings and does not depend on integer-casted values.
An int has an upper limit, and bigger numbers will be represented as floats, which are imprecise and therefore a bad idea to use in this situation. Use a string to store such numbers and the BC Math extension if you need to do calculations on it.
Unfornuately PHP int type can only go upto 2147483647 but PHP float can hold integers upto 10000000000000
Check out php.net
http://php.net/manual/en/language.types.integer.php
UPDATE
PHP.net says that a float can accurately hold an integer upto 10000000000000. Im not sure if float has an upper limit though.
One option is to run PHP on a 64bit OS as the in size is determined by the underlying operating system. This is obviously dependent if you can get access to 64bit hardware, one thing to note is that this will be faster than using gmp/bcmath but unless pure speed is your aim it probably won't be an issue for you

PHP String to Float

I am not familiar with PHP at all and had a quick question.
I have 2 variables pricePerUnit and InvoicedUnits. Here's the code that is setting these to values:
$InvoicedUnits = ((string) $InvoiceLineItem->InvoicedUnits);
$pricePerUnit = ((string) $InvoiceLineItem->PricePerUnit);
If I output this, I get the correct values. Lets say 5000 invoiced units and 1.00 for price.
Now, I need to show the total amount spent. When I multiply these two together it doesn't work (as expected, these are strings).
But I have no clue how to parse/cast/convert variables in PHP.
What should I do?
$rootbeer = (float) $InvoicedUnits;
Should do it for you. Check out Type-Juggling. You should also read String conversion to Numbers.
You want the non-locale-aware floatval function:
float floatval ( mixed $var ) - Gets the float value of a string.
Example:
$string = '122.34343The';
$float = floatval($string);
echo $float; // 122.34343
Well, if user write 1,00,000 then floatvar will show error. So -
floatval(preg_replace("/[^-0-9\.]/","",$input));
This is much more reliable.
Usage :
$input = '1,03,24,23,434,500.6798633 this';
echo floatval(preg_replace("/[^-0-9\.]/","",$input));
Dealing with markup in floats is a non trivial task. In the English/American notation you format one thousand plus 46*10-2:
1,000.46
But in Germany you would change comma and point:
1.000,46
This makes it really hard guessing the right number in multi-language applications.
I strongly suggest using Zend_Measure of the Zend Framework for this task. This component will parse the string to a float by the users language.
you can follow this link to know more about How to convert a string/number into number/float/decimal in PHP.
HERE IS WHAT THIS LINK SAYS...
Method 1: Using number_format() Function. The number_format() function is used to convert a string into a number. It returns the formatted number on success otherwise it gives E_WARNING on failure.
$num = "1000.314";
//Convert string in number using
//number_format(), function
echo number_format($num), "\n";
//Convert string in number using
//number_format(), function
echo number_format($num, 2);
Method 2: Using type casting: Typecasting can directly convert a string into a float, double, or integer primitive type. This is the best way to convert a string into a number without any function.
// Number in string format
$num = "1000.314";
// Type cast using int
echo (int)$num, "\n";
// Type cast using float
echo (float)$num, "\n";
// Type cast using double
echo (double)$num;
Method 3: Using intval() and floatval() Function. The intval() and floatval() functions can also be used to convert the string into its corresponding integer and float values respectively.
// Number in string format
$num = "1000.314";
// intval() function to convert
// string into integer
echo intval($num), "\n";
// floatval() function to convert
// string to float
echo floatval($num);
Method 4: By adding 0 or by performing mathematical operations. The string number can also be converted into an integer or float by adding 0 with the string. In PHP, performing mathematical operations, the string is converted to an integer or float implicitly.
// Number into string format
$num = "1000.314";
// Performing mathematical operation
// to implicitly type conversion
echo $num + 0, "\n";
// Performing mathematical operation
// to implicitly type conversion
echo $num + 0.0, "\n";
// Performing mathematical operation
// to implicitly type conversion
echo $num + 0.1;
Use this function to cast a float value from any kind of text style:
function parseFloat($value) {
return floatval(preg_replace('#^([-]*[0-9\.,\' ]+?)((\.|,){1}([0-9-]{1,3}))*$#e', "str_replace(array('.', ',', \"'\", ' '), '', '\\1') . '.\\4'", $value));
}
This solution is not dependant on any locale settings. Thus for user input users can type float values in any way they like. This is really helpful e.g. when you have a project wich is in english only but people all over the world are using it and might not have in mind that the project wants a dot instead of a comma for float values.
You could throw javascript in the mix and fetch the browsers default settings but still many people set these values to english but still typing 1,25 instead of 1.25 (especially but not limited to the translation industry, research and IT)
I was running in to a problem with the standard way to do this:
$string = "one";
$float = (float)$string;
echo $float; : ( Prints 0 )
If there isn't a valid number, the parser shouldn't return a number, it should throw an error. (This is a condition I'm trying to catch in my code, YMMV)
To fix this I have done the following:
$string = "one";
$float = is_numeric($string) ? (float)$string : null;
echo $float; : ( Prints nothing )
Then before further processing the conversion, I can check and return an error if there wasn't a valid parse of the string.
For the sake of completeness, although this question is ancient, it's worth mentioning the filter_var() set of functions, which should not only handle the formatting bits itself, but also validate or sanitise the output, thus being safer to use in the context of a form being filled in by users (or, eventually, a database that might have some corrupted/inconsistent fields):
$InvoicedUnits = (float) filter_var($InvoiceLineItem->InvoicedUnits,
FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
$pricePerUnit = (float) filter_var($InvoiceLineItem->PricePerUnit,
FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
printf("The total is: %.2f\n", $InvoicedUnits * $pricePerUnit); // both are now floats and the result is a float, formatted to two digits after the decimal sign.
This sanitises the output (which will still remain a string) and will accept the current locale's setting of the decimal separator (e.g. dot vs. comma); also, there are more options on the PHP manual for validation (which will automatically convert the result to a float if valid). The results will be slightly different for different scenarios — e.g. if you know in advance that the $InvoiceLineItem will only have valid digits and symbols for floating-point numbers, or if you need to 'clean up' the field first, getting rid of whitespace, stray characters (such as currency symbols!), and so forth.
Finally, if you wish to have nicely-formatted output — since the total is expressed in a currency — you should also take a look at the built-in NumberFormatter class, and do something like:
$InvoicedUnits = (float) filter_var($InvoiceLineItem->InvoicedUnits,
FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
$pricePerUnit = (float) filter_var($InvoiceLineItem->PricePerUnit,
FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
$fmt = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);
echo 'Total is: ' . $fmt->formatCurrency($InvoicedUnits * $pricePerUnit, 'EUR') . PHP_EOL;
This will also handle thousand separators (spaces, dots, commas...) according to the configured locale, and other similar fancy things.
Also, if you wish, you can use '' (the empty string) for the default locale string (set either by the server or optionally by the browser) and $fmt->getSymbol(NumberFormatter::INTL_CURRENCY_SYMBOL) to get the default 3-letter currency code (which might not be what you want, since usually prices are given in a specific currency — these functions do not take currency exchange rates into account!).
If you need to handle values that cannot be converted separately, you can use this method:
try {
// use + 0 if you are accounting in cents
$doubleValue = trim($stringThatMightBeNumeric) + 0.0;
} catch (\Throwable $th) {
// bail here if you need to
}

Categories