PHPSpreadsheet and writing large numbers of decimal places - php

I'm having difficulty with PHPSpreadsheet when creating an XLSX file and attempting to write large numbers of decimal places to numerical values.
PHPSpreadsheet is rounding my 14 decimal place numbers, but I need them stored exactly as presented.
I'm using setFormatCode('0.00000000000000') as described in the documentation, but it's not working as I would expect.
Here's my test code:
<?php
require __DIR__ . '/vendor/autoload.php'; // Installed via composer
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$array = [
0.03790728347833,
1345.28748532874927,
121345.18248762894914, // all 14 DP
];
$format = '0.00000000000000'; // 14 DP
// write the data
$spreadsheet->getActiveSheet()
->fromArray($array, null, 'A1');
// Format the cells
$spreadsheet->getActiveSheet()->getStyle('A1:C1')->getNumberFormat()->setFormatCode($format);
// Column sizing
foreach(range('A','C') as $columnID)
{
$spreadsheet->getActiveSheet()->getColumnDimension($columnID)->setAutoSize(true);
}
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->save("test.xlsx");
// A1 = 0.03790728347833 - same
// A2 = 1345.28748532870000 - rounded
// A3 = 121345.18248763000000 - rounded
Could anyone provide a way to store this many decimal places without rounding?

This appears to be a limitation of Excel rather than PHPSpreadsheet.
Excel is limited to 15 significant figures according to Wikipedia.

Related

shuchkin/simplexlsxgen, how to prevent Decimal dott from changing to comma

i am using (shuchkin/simplexlsxgen) to generate xlsx file which works fine.
My data contain decimal numbers such as (0.19) which are written in the SQL DB, but instead writting them with dott, the (simplexlsxgen) convert them to (0,19) comma decimal numbers.
is there a way to prevent changing the decimal Dott to comma, before generating?
Thanks in advance.
//convert test_bulk.csv to Xlsx
function csvToArray($csvFile)
{
$file_to_read = fopen($csvFile, 'r');
while (!feof($file_to_read))
{
$lines[] = fgetcsv($file_to_read, 1000, ';');
}
fclose($file_to_read);
return $lines;
}
//read the csv file into an array
$csvFile = 'test_bulk.csv';
$csv = csvToArray($csvFile);
Shuchkin\SimpleXLSXGen::fromArray($csv)->saveAs('final_bulk.xlsx');
by adding "\0". before the targeted string, it will turn it to be a RAW STRING. which will make this super Tool write it without changing the decimal dott to comma.
you all gotta try this amazing fast effective tool by the PHP Excel Old school Master (Sergey Shuchkin).
https://github.com/shuchkin

convert number with decimals without

I make a query to mysql and I get this number:
26,613,080
and I need to convert that number to:
266,130 or 266.130 (it does not matter if it is , or . )
I was doing some tests with number format or removing the last 2 numbers but I can't get it to stay as I need.
Thanks
If you have the intl extension installed, you can use the NumberFormatter class for this.
$input = "26,613,080";
$numberFormatter = new NumberFormatter("en_EN", NumberFormatter::DECIMAL);
$numberValue = $numberFormatter->parse($input);
var_dump($numberValue);
// float(26613080)
// I'm using TYPE_INT32 because that removes the decimal digits without rounding.
$output = $numberFormatter->format($numberValue / 100, NumberFormatter::TYPE_INT32);
var_dump($output);
// string(7) "266,130"

How to define a custom base of numbers in php?

I need to define new number base for my custom calculations,
I have an order list of 11 chars (lets say a,h,k,d,e,f,g,z,i,j,m)
I want to to be able to perform mathematics tasks on them like they were a number base.
For example a+h=k, a+k=d, j++=m and etc...
Is this possible?
The best way I thought of is taking regular base of 11 and just replace all chars before and after the calculation it self (so j++ would be actually 9++=a and then a will be translated into m).
This way is not very efficient but will work.
Any better ideas?
Thank you.
PHP offers to perform math operations for decimal, octal, hexadecimal and binary numbers natively. If you want to do calculations with other kinds of number systems you need to convert them to one of the above kinds.
Basically you are using a base11 number system - having custom digits. PHP offers the function base_convert() to convert numbers between systems with a different base. Having this, you just need to translate your custom digits to base11 then base11 to decimal then calculate and then convert it back.
Hackish!, but it can be done like this.
function add($a, $b) {
$custom_digits = 'ahkdefgzijm';
$base11_digits = '0123456789A';
// translate custom numbers to base11
$base11_a = strtr($a, $custom_digits, $base11_digits);
$base11_b = strtr($a, $custom_digits, $base11_digits);
// translate base11 numbers to decimal
$decimal_a = base_convert($base11_a, 11, 10);
$decimal_b = base_convert($base11_b, 11, 10);
// Do the calculation
$result = $decimal_a + $decimal_b;
// Convert result back to base11
$base11_result = base_convert($result, 10, 11);
// Translate base11 result into customer digits
return strtr($base11_result, $base11_digits, $custom_digits);
}
And never forget!:
h + h == k
:)
A more flexible attempt could be to create two functions like this:
function dec_to_custom($n) {
static $custom_digits = 'ahkdefgzijm';
static $base11_digits = '0123456789a';
return strtr(base_convert($n, 10, 11), $base11_digits, $custom_digits);
}
function custom_to_dec($n) {
static $custom_digits = 'ahkdefgzijm';
static $base11_digits = '0123456789a';
$base11 = strtr($n, $custom_digits, $base11_digits);
return base_convert($base11, 11, 10);
}
And the use them like you wish in (integer!) math operations:
echo dec_to_custom(custom_to_dec(1) + custom_to_dec(1));
Update
Looks like I answered too fast. You had already a solution like I suggested and you are concerned about the strtr() usage. I can only say that I did a similar task once and did a lot of profiling and ended up using strtr() since it showed the best performance.

How can I ensure unique file names for images uploaded to server?

I'm creating a web application that allows users to upload images to a server.
How can I prevent duplicate image file names when a user uploads images?
How can I change the filename to a unique name that is no duplicate of any previous image's name (or next image that might be uploaded)?
Editing :
if i user primary key autoincrement as image filename for each images ? is it will be useful ?
I already answered such question before. And I updated my code to add more randomness (entropy) to the generated id.
This class generate pseudo-unique, non-sequential, non-numeric IDs.
class IdGenerator {
static private function _nextChar() {
return base_convert(mt_rand(0, 35), 10, 36);
}
static public function generate() {
$parts = explode('.', uniqid('', true));
$id = str_pad(base_convert($parts[0], 16, 2), 56, mt_rand(0, 1), STR_PAD_LEFT)
. str_pad(base_convert($parts[1], 10, 2), 32, mt_rand(0, 1), STR_PAD_LEFT);
$id = str_pad($id, strlen($id) + (8 - (strlen($id) % 8)), mt_rand(0, 1), STR_PAD_BOTH);
$chunks = str_split($id, 8);
$id = array();
foreach ($chunks as $key => $chunk) {
if ($key & 1) { // odd
array_unshift($id, $chunk);
} else { // even
array_push($id, $chunk);
}
}
// add random seeds
$prefix = str_pad(base_convert(mt_rand(), 10, 36), 6, self::_nextChar(), STR_PAD_BOTH);
$id = str_pad(base_convert(implode($id), 2, 36), 19, self::_nextChar(), STR_PAD_BOTH);
$suffix = str_pad(base_convert(mt_rand(), 10, 36), 6, self::_nextChar(), STR_PAD_BOTH);
return $prefix . self::_nextChar() . $id . $suffix;
}
}
If you execute this script
header('Content-type: text/plain; charset=utf-8');
for ($i=0; $i<10; $i++) {
$uid = IdGenerator::generate();
echo $uid . " = " . strlen($uid) . "\n";
}
You will get something like this :
x0i8eea3c8kw4lgudmoss4c4w03db6wl = 32
byqrfgc6hilr9d1ot4wow8gw4syugtvz = 32
ta075al22zp3v6awtlw4kgkk446mjbiv = 32
hqqa90p27e9desx99q8skokcc46fujx4 = 32
uqc000q7g20l1k9zlwko80gsow5e59e7 = 32
gxx2r5d5oa0p8iykvc4ckgc4kc0teekv = 32
ayysoos5ltfua3d0m80ccocc0kcfhqyb = 32
dtj31vi4tzmh6lhk1iccc0os4cgsze1e = 32
fvn41hh2gnk6lbrq4w0wwgko8k5ihda8 = 32
oxamsba3qh0ro6xehkw8cg400s10tiyq = 32
** Edit **
So, why all this? Why not just use uniqid()? Because uniqid() is sequential and is predictable. Because you need to add more entropy. This class not only use uniqid() "more entropy" argument, it also uses mt_rand() to pad the generated values with it. The class provided here will also always generate a 32 bytes (256-bits) string.
How random this function is? To have a duplicate ID, one would need to call uniqid() at the exact same time, and mt_rand() would need to return the exact same random values in the same order... seven times in a row. The bottom line is that it is quite random.
** Edit 2 **
You may also be interested by a pure PHP UUID implementation.
** Edit 3 **
The problem with using a Primary Key (PK) as unique file name is that it is predictable. If you intend to serve these files directly from URI routes, then a generated non-sequential value is safer. If you intend to serve these files otherwise, then these files will have to be assigned some unique key anyhow... and this key cannot be sequential for the exact same reasons. So, regardless the use case, having a non-sequential unique key as file name is a good idea.
The easiest way that guarantees unique filenames is to use a simple sequence that increases for every new image.
Sequence
If you use a database like MySQL to store additional information to the images you could just use the automatically assigned ID of a primary key column with AUTO_INCREMENT or you can also just store the current sequence value in a simple text file.
Note, that the option using a file to store the current value is dangerous because by simply accessing it, two concurrent file uploads could yield the same filename. You could use file locks (see docs of flock) to circumvent this but that could be inefficient.
Hashing Functions
Using hashing functions is not guaranteed to yield unique ids since two different inputs can generate the same output (with some usually low probability). Also the timestamp only might be to inaccurate and therefore result in the same filename if two files are uploaded in a very small timeframe.
You can use the MD5 of the current timestamp * random for example
$date = date('Y-m-d H:i:s');
$filename = md5(uniqid($date, true) * rand()) . ".png";
Also have a look here: PHP: How to generate a random, unique, alphanumeric string?
And here: http://php.net/uniqid

PHPExcel - read time value from a cell

I'm loading an Excel file that has cells with time data, e.g. 08:00:00. But when I try to read those cells with getValue(), it returns some floating point numbers instead of the actual time (in case of 08:00:00, it returns 0.3333333). Here's my code:
$objPHPExcel = PHPExcel_IOFactory::load($filename);
$objWorksheet = $objPHPExcel->getActiveSheet();
echo $objWorksheet->getCellByColumnAndRow(3, 5)->getValue();
How do I bypass this weird conversion?
PHPExcel 1.7.6 and Excel 2003 Worksheet (.xls)
You need to apply cell format for this:
$cell = $objWorksheet->getCellByColumnAndRow(3, 5);
$cell_value = PHPExcel_Style_NumberFormat::toFormattedString($cell->getCalculatedValue(), 'hh:mm:ss');
echo $cell_value;

Categories