Skip to content

Commit

Permalink
Validate POST Data in Sample 45
Browse files Browse the repository at this point in the history
Errors can result if not validated.
  • Loading branch information
oleibman committed Sep 8, 2024
1 parent 949ff63 commit bc74f3a
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 21 deletions.
6 changes: 4 additions & 2 deletions samples/Basic4/45_Quadratic_equation_solver.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
}
?>
<form action="45_Quadratic_equation_solver.php" method="POST">
Enter the coefficients for the Ax<sup>2</sup> + Bx + C = 0
Enter the coefficients for Ax<sup>2</sup> + Bx + C = 0
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
Expand Down Expand Up @@ -47,7 +47,9 @@
<?php
/** If the user has submitted the form, then we need to execute a calculation * */
if (isset($_POST['submit'])) {
if ($_POST['A'] == 0) {
if (!is_numeric($_POST['A']) || !is_numeric($_POST['B']) || !is_numeric($_POST['C'])) { // validate input
$helper->log('Non-numeric input');
} elseif ($_POST['A'] == 0) {
$helper->log('The equation is not quadratic');
} else {
// Calculate and Display the results
Expand Down
4 changes: 1 addition & 3 deletions src/PhpSpreadsheet/Calculation/Financial/Amortization.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

class Amortization
{
private const ROUNDING_ADJUSTMENT = (PHP_VERSION_ID < 80400) ? 0 : 1e-14;

/**
* AMORDEGRC.
*
Expand Down Expand Up @@ -82,7 +80,7 @@ public static function AMORDEGRC(
$amortiseCoeff = self::getAmortizationCoefficient($rate);

$rate *= $amortiseCoeff;
$rate += self::ROUNDING_ADJUSTMENT;
$rate = (float) (string) $rate; // ugly way to avoid rounding problem
$fNRate = round($yearFrac * $rate * $cost, 0);
$cost -= $fNRate;
$fRest = $cost - $salvage;
Expand Down
33 changes: 27 additions & 6 deletions src/PhpSpreadsheet/Calculation/MathTrig/Round.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ class Round
{
use ArrayEnabled;

private const ROUNDING_ADJUSTMENT = (PHP_VERSION_ID < 80400) ? 0 : 1e-14;

/**
* ROUND.
*
Expand Down Expand Up @@ -69,11 +67,22 @@ public static function up($number, $digits): array|string|float
return 0.0;
}

$digitsPlus1 = $digits + 1;
if ($number < 0.0) {
return round($number - 0.5 * 0.1 ** $digits + self::ROUNDING_ADJUSTMENT, $digits, PHP_ROUND_HALF_DOWN);
if ($digitsPlus1 < 0) {
return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN);
}
$result = sprintf("%.{$digitsPlus1}F", $number - 0.5 * 0.1 ** $digits);

return round((float) $result, $digits, PHP_ROUND_HALF_DOWN);
}

if ($digitsPlus1 < 0) {
return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN);
}
$result = sprintf("%.{$digitsPlus1}F", $number + 0.5 * 0.1 ** $digits);

return round($number + 0.5 * 0.1 ** $digits - self::ROUNDING_ADJUSTMENT, $digits, PHP_ROUND_HALF_DOWN);
return round((float) $result, $digits, PHP_ROUND_HALF_DOWN);
}

/**
Expand Down Expand Up @@ -105,11 +114,23 @@ public static function down($number, $digits): array|string|float
return 0.0;
}

$digitsPlus1 = $digits + 1;
if ($number < 0.0) {
return round($number + 0.5 * 0.1 ** $digits - self::ROUNDING_ADJUSTMENT, $digits, PHP_ROUND_HALF_UP);
if ($digitsPlus1 < 0) {
return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP);
}
$result = sprintf("%.{$digitsPlus1}F", $number + 0.5 * 0.1 ** $digits);

return round((float) $result, $digits, PHP_ROUND_HALF_UP);
}

if ($digitsPlus1 < 0) {
return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP);
}

return round($number - 0.5 * 0.1 ** $digits + self::ROUNDING_ADJUSTMENT, $digits, PHP_ROUND_HALF_UP);
$result = sprintf("%.{$digitsPlus1}F", $number - 0.5 * 0.1 ** $digits);

return round((float) $result, $digits, PHP_ROUND_HALF_UP);
}

/**
Expand Down
29 changes: 23 additions & 6 deletions src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ class Trunc
* TRUNC.
*
* Truncates value to the number of fractional digits by number_digits.
* This will probably not be the precise result in the unlikely
* event that the number of digits to the left of the decimal
* plus the number of digits to the right exceeds PHP_FLOAT_DIG
* (or possibly that value minus 1).
* Excel is unlikely to do any better.
*
* @param array|float $value Or can be an array of values
* @param array|int $digits Or can be an array of values
Expand All @@ -34,15 +39,27 @@ public static function evaluate(array|float|string|null $value = 0, array|int|st
return $e->getMessage();
}

$digits = floor($digits);
if ($value == 0) {
return $value;
}

// Truncate
$adjust = 10 ** $digits;
if ($value >= 0) {
$minusSign = '';
} else {
$minusSign = '-';
$value = -$value;
}
$digits = (int) floor($digits);
if ($digits < 0) {
$result = (float) (substr(sprintf('%.0F', $value), 0, $digits) . str_repeat('0', -$digits));

if (($digits > 0) && (rtrim((string) (int) ((abs($value) - abs((int) $value)) * $adjust), '0') < $adjust / 10)) {
return $value;
return ($minusSign === '') ? $result : -$result;
}
$decimals = (floor($value) == (int) $value) ? (PHP_FLOAT_DIG - strlen((string) (int) $value)) : $digits;
$resultString = ($decimals < 0) ? sprintf('%F', $value) : sprintf('%.' . $decimals . 'F', $value);
$regExp = '/([.]\\d{' . $digits . '})\\d+$/';
$result = $minusSign . (preg_replace($regExp, '$1', $resultString) ?? $resultString);

return ((int) ($value * $adjust)) / $adjust;
return (float) $result;
}
}
7 changes: 6 additions & 1 deletion src/PhpSpreadsheet/Helper/Sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\IWriter;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Dompdf;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RecursiveRegexIterator;
Expand Down Expand Up @@ -129,7 +130,11 @@ public function write(Spreadsheet $spreadsheet, string $filename, array $writers
$writerCallback($writer);
}
$callStartTime = microtime(true);
$writer->save($path);
if (PHP_VERSION_ID >= 80400 && $writer instanceof Dompdf) {
@$writer->save($path);
} else {
$writer->save($path);
}
$this->logWrite($writer, $path, $callStartTime);
if ($this->isCli() === false) {
// @codeCoverageIgnoreStart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,36 @@ public static function providerTruncArray(): array
'matrix' => [[[3.14, 3.141], [3.14159, 3.14159265]], '3.1415926536', '{2, 3; 5, 8}'],
];
}

/**
* @dataProvider providerTooMuchPrecision
*/
public function testTooMuchPrecision(mixed $expectedResult, float|int|string $value, int $digits = 1): void
{
// This test is pretty screwy. Possibly shouldn't even attempt it.
// At any rate, these results seem to indicate that PHP
// maximum precision is PHP_FLOAT_DIG - 1 digits, not PHP_FLOAT_DIG.
// If that changes, at least one of these tests will have to change.
$sheet = $this->getSheet();
$sheet->getCell('E1')->setValue($value);
$sheet->getCell('E2')->setValue("=TRUNC(E1,$digits)");
$result = $sheet->getCell('E2')->getCalculatedValue();
self::assertSame($expectedResult, (string) $result);
}

public static function providerTooMuchPrecision(): array
{
$max64Plus1 = 9223372036854775808;
$stringMax = (string) $max64Plus1;

return [
'2 digits less than PHP_FLOAT_DIG' => ['1' . str_repeat('0', PHP_FLOAT_DIG - 4) . '1.2', 10.0 ** (PHP_FLOAT_DIG - 3) + 1.2, 1],
'1 digit less than PHP_FLOAT_DIG' => ['1' . str_repeat('0', PHP_FLOAT_DIG - 3) . '1', 10.0 ** (PHP_FLOAT_DIG - 2) + 1.2, 1],
'PHP_FLOAT_DIG' => ['1.0E+' . (PHP_FLOAT_DIG - 1), 10.0 ** (PHP_FLOAT_DIG - 1) + 1.2, 1],
'1 digit more than PHP_FLOAT_DIG' => ['1.0E+' . PHP_FLOAT_DIG, 10.0 ** PHP_FLOAT_DIG + 1.2, 1],
'32bit exceed int max' => ['3123456780', 3123456789, -1],
'64bit exceed int max neg decimals' => [$stringMax, $max64Plus1, -1],
'64bit exceed int max pos decimals' => [$stringMax, $max64Plus1, 1],
];
}
}
12 changes: 11 additions & 1 deletion tests/PhpSpreadsheetTests/Functional/StreamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;

/**
* Not clear that Dompdf will be Php8.4 compatible in time.
* Run in separate process and add version test till it is ready.
*
* @runTestsInSeparateProcesses
*/
class StreamTest extends TestCase
{
public static function providerFormats(): array
Expand Down Expand Up @@ -42,7 +48,11 @@ public function testAllWritersCanWriteToStream(string $format): void
} else {
self::assertSame(0, $stat['size']);

$writer->save($stream);
if ($format === 'Dompdf' && PHP_VERSION_ID >= 80400) {
@$writer->save($stream);
} else {
$writer->save($stream);
}

self::assertIsResource($stream, 'should not close the stream for further usage out of PhpSpreadsheet');
$stat = fstat($stream);
Expand Down
18 changes: 16 additions & 2 deletions tests/PhpSpreadsheetTests/Writer/Dompdf/PaperSizeArrayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Dompdf;
use PHPUnit\Framework\TestCase;

/**
* Not clear that Dompdf will be Php8.4 compatible in time.
* Run in separate process and add version test till it is ready.
*
* @runTestsInSeparateProcesses
*/
class PaperSizeArrayTest extends TestCase
{
private string $outfile = '';
Expand All @@ -36,7 +42,11 @@ public function testPaperSizeArray(): void
$sheet->setCellValue('A7', 'Lorem Ipsum');
$writer = new Dompdf($spreadsheet);
$this->outfile = File::temporaryFilename();
$writer->save($this->outfile);
if (PHP_VERSION_ID >= 80400) { // hopefully temporary
@$writer->save($this->outfile);
} else {
$writer->save($this->outfile);
}
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
$contents = file_get_contents($this->outfile);
Expand All @@ -56,7 +66,11 @@ public function testPaperSizeNotArray(): void
$sheet->setCellValue('A7', 'Lorem Ipsum');
$writer = new Dompdf($spreadsheet);
$this->outfile = File::temporaryFilename();
$writer->save($this->outfile);
if (PHP_VERSION_ID >= 80400) { // hopefully temporary
@$writer->save($this->outfile);
} else {
$writer->save($this->outfile);
}
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
$contents = file_get_contents($this->outfile);
Expand Down
1 change: 1 addition & 0 deletions tests/data/Calculation/MathTrig/ROUNDDOWN.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@
[0, 'B1, 0'],
['exception', ''],
['exception', '35.51'],
'negative number and precision' => [-31400, '-31415.92654, -2'],
];
1 change: 1 addition & 0 deletions tests/data/Calculation/MathTrig/ROUNDUP.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@
[0, 'B1, 0'],
['exception', ''],
['exception', '35.51'],
'negative number and precision' => [-31500, '-31415.92654, -2'],
];
20 changes: 20 additions & 0 deletions tests/data/Calculation/MathTrig/TRUNC.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
[-31415.92654, '-31415.92654, 10'],
[31415.92, '31415.92654, 2'],
[31400, '31415.92654, -2'],
'negative number and precision' => [-31400, '-31415.92654, -2'],
[0, '31415.92654, -10'],
[0, '-31415.92654, -10'],
[12000, '12345.6789, -3'],
Expand All @@ -32,4 +33,23 @@
[-3, 'A4'],
[-5, 'A5'],
[0, 'B1'],
'issue4113' => [1.0, '1.01, 1'],
'issue4113 negative' => [-1.0, '-1.01, 1'],
'issue4113 additional' => [10.04, '10.04, 2'],
'issue4113 additional negative' => [-10.04, '-10.04, 2'],
'issue4113 small fraction keep all' => [0.04, '0.04, 2'],
'issue4113 small negative fraction keep all' => [-0.04, '-0.04, 2'],
'issue4113 small fraction lose some' => [0.0, '0.01, 1'],
'issue4113 small negative fraction lose some' => [0.0, '-0.001, 1'],
'issue4113 example 3' => [-43747, '-43747.99122596, 0'],
'issue4113 example 3 positive' => [43747, '43747.99122596, 0'],
'issue4113 example 4' => [-9.11, '-9.1196419, 2'],
'issue4113 example 5' => [-42300.65, '-42300.65099338, 3'],
'issue4113 example 6 variant 1' => [0.000012, '0.0000123, 6'],
'issue4113 example 6 variant 2' => [0.0000123, '0.0000123, 8'],
'issue4113 example 6 variant 3' => [-0.000012, '-0.0000123, 6'],
'issue4113 example 6 variant 4' => [-0.0000123, '-0.0000123, 8'],
'issue4113 example 6 variant 5' => [0.000012, '1.23E-5, 6'],
'issue4113 example 6 variant 6' => [-0.0000123, '-1.23E-5, 8'],
'exceed 32-bit int max' => [3123456780, '3123456789, -1'],
];

0 comments on commit bc74f3a

Please sign in to comment.