Abbreviate Number Function Won't Output Negative Value - php

So I have this class, which appreciates numbers. For example, AbbreviateNum::convert(1178); will round up and turn it into 1.18K.
This works as it should, nicely. However, I can't seem to figure out how to output negative numbers. If I run AbbreviateNum::convert(-1178);, it will output the same response 1.18K. Without the negative indicator.
Any tips on how I fix this?
<?php
namespace App\Helpers;
class AbbreviateNum
{
/**
* Abbreviate long numbers
*
* #return Response
*/
public static function convert($num)
{
$num = preg_replace('/[^0-9]/', '', $num);
$sizes = array("", "K", "M");
if ($num == 0) return(0);
else return (round($num/pow(1000, ($i = floor(log($num, 1000)))), 2) . $sizes[$i]);
}
}

Here is the modified function that provides a little bit more robustness for the strings it will accept.
public static function convert($num)
{
$num = intval(preg_replace('/[^\-\.0-9]/', '', $num));
$sizes = array("", "K", "M");
if ($num == 0) return(0);
else return (round($num/pow(1000, ($i = floor(log(abs($num), 1000)))), 2) . $sizes[abs($i)]);
}

Simply change the name of the convert Method's argument (num) & do a simple strstr() Check for "-". If found, prefix you result with "-" like this:
<?php
namespace App\Helpers;
class AbbreviateNum
{
/**
* Abbreviate long numbers
*
* #return Response
*/
public static function convert($givenNumber){
$num = preg_replace('/[^0-9]/', '', $givenNumber);
$sizes = array("", "K", "M");
if ($num == 0) {
return(0);
}else {
$number = (round($num/pow(1000, ($i = floor(log($num, 1000)))), 2) . $sizes[$i]);
if(strstr($givenNumber, "-")){
$number = "-" . $number;
}
return $number;
}
}
}
var_dump(AbbreviateNum::convert(-1785));
// PRODUCES: string '-1.79K' (length=6)
var_dump(AbbreviateNum::convert(1785));
// PRODUCES: string '1.79K' (length=5)
Confirm it HERE.
Hope this helps a bit...
Cheers & Good Luck ;-)

For such conversion, I'd use sprintf function:
public static function convert($num) {
$sizes = array("", "K", "M", "G", "T");
$i = 0;
$res = $num;
while (abs($num) > 1000) {$num /= 1000; $i++; $res = sprintf("%.2f$sizes[$i]", $num);}
return $res;
}

Related

SQL and PHP: Is it possible to convert a string to binary without using SQL function [duplicate]

I got the problem when convert between this 2 type in PHP. This is the code I searched in google
function strToHex($string){
$hex='';
for ($i=0; $i < strlen($string); $i++){
$hex .= dechex(ord($string[$i]));
}
return $hex;
}
function hexToStr($hex){
$string='';
for ($i=0; $i < strlen($hex)-1; $i+=2){
$string .= chr(hexdec($hex[$i].$hex[$i+1]));
}
return $string;
}
I check it and found out this when I use XOR to encrypt.
I have the string "this is the test", after XOR with a key, I have the result in string ↕↑↔§P↔§P ♫§T↕§↕. After that, I tried to convert it to hex by function strToHex() and I got these 12181d15501d15500e15541215712. Then, I tested with the function hexToStr() and I have ↕↑↔§P↔§P♫§T↕§q. So, what should I do to solve this problem? Why does it wrong when I convert this 2 style value?
For people that end up here and are just looking for the hex representation of a (binary) string.
bin2hex("that's all you need");
# 74686174277320616c6c20796f75206e656564
hex2bin('74686174277320616c6c20796f75206e656564');
# that's all you need
Doc: bin2hex, hex2bin.
For any char with ord($char) < 16 you get a HEX back which is only 1 long. You forgot to add 0 padding.
This should solve it:
<?php
function strToHex($string){
$hex = '';
for ($i=0; $i<strlen($string); $i++){
$ord = ord($string[$i]);
$hexCode = dechex($ord);
$hex .= substr('0'.$hexCode, -2);
}
return strToUpper($hex);
}
function hexToStr($hex){
$string='';
for ($i=0; $i < strlen($hex)-1; $i+=2){
$string .= chr(hexdec($hex[$i].$hex[$i+1]));
}
return $string;
}
// Tests
header('Content-Type: text/plain');
function test($expected, $actual, $success) {
if($expected !== $actual) {
echo "Expected: '$expected'\n";
echo "Actual: '$actual'\n";
echo "\n";
$success = false;
}
return $success;
}
$success = true;
$success = test('00', strToHex(hexToStr('00')), $success);
$success = test('FF', strToHex(hexToStr('FF')), $success);
$success = test('000102FF', strToHex(hexToStr('000102FF')), $success);
$success = test('↕↑↔§P↔§P ♫§T↕§↕', hexToStr(strToHex('↕↑↔§P↔§P ♫§T↕§↕')), $success);
echo $success ? "Success" : "\nFailed";
PHP :
string to hex:
implode(unpack("H*", $string));
hex to string:
pack("H*", $hex);
Here's what I use:
function strhex($string) {
$hexstr = unpack('H*', $string);
return array_shift($hexstr);
}
function hexToStr($hex){
// Remove spaces if the hex string has spaces
$hex = str_replace(' ', '', $hex);
return hex2bin($hex);
}
// Test it
$hex = "53 44 43 30 30 32 30 30 30 31 37 33";
echo hexToStr($hex); // SDC002000173
/**
* Test Hex To string with PHP UNIT
* #param string $value
* #return
*/
public function testHexToString()
{
$string = 'SDC002000173';
$hex = "53 44 43 30 30 32 30 30 30 31 37 33";
$result = hexToStr($hex);
$this->assertEquals($result,$string);
}
Using #bill-shirley answer with a little addition
function str_to_hex($string) {
$hexstr = unpack('H*', $string);
return array_shift($hexstr);
}
function hex_to_str($string) {
return hex2bin("$string");
}
Usage:
$str = "Go placidly amidst the noise";
$hexstr = str_to_hex($str);// 476f20706c616369646c7920616d6964737420746865206e6f697365
$strstr = hex_to_str($str);// Go placidly amidst the noise
You can try the following code to convert the image to hex string
<?php
$image = 'sample.bmp';
$file = fopen($image, 'r') or die("Could not open $image");
while ($file && !feof($file)){
$chunk = fread($file, 1000000); # You can affect performance altering
this number. YMMV.
# This loop will be dog-slow, almost for sure...
# You could snag two or three bytes and shift/add them,
# but at 4 bytes, you violate the 7fffffff limit of dechex...
# You could maybe write a better dechex that would accept multiple bytes
# and use substr... Maybe.
for ($byte = 0; $byte < strlen($chunk); $byte++)){
echo dechex(ord($chunk[$byte]));
}
}
?>
I only have half the answer, but I hope that it is useful as it adds unicode (utf-8) support
/**
* hexadecimal to unicode character
* #param string $hex
* #return string
*/
function hex2uni($hex) {
$dec = hexdec($hex);
if($dec < 128) {
return chr($dec);
}
if($dec < 2048) {
$utf = chr(192 + (($dec - ($dec % 64)) / 64));
} else {
$utf = chr(224 + (($dec - ($dec % 4096)) / 4096));
$utf .= chr(128 + ((($dec % 4096) - ($dec % 64)) / 64));
}
return $utf . chr(128 + ($dec % 64));
}
To string
var_dump(hex2uni('e641'));
Based on: http://www.php.net/manual/en/function.chr.php#Hcom55978

Implement counter with digits and letters in php [duplicate]

I need to generate a sequence (or function to get a "next id") with an alphanumeric incrementor.
The length of the string must be defineable, and the Characters must be 0-9, A-Z.
So for example, with a length of 3:
000
001
002
~
009
00A
00B
~
00Z
010
011
etc..
So I imagine the function might be used like this:
$code = '009'
$code = getNextAlphaNumeric($code);
ehco $code; // '00A'
I'm working on a solution to this myself, but curious if anyone has tackled this before and come up with a smarter / more robust solution than my own.
Does anyone have a nice solution to this problem?
Would something like base_convert work? Maybe along these lines (untested)
function getNextAlphaNumeric($code) {
$base_ten = base_convert($code,36,10);
return base_convert($base_ten+1,10,36);
}
The idea is that your codes are all really just a base 36 number, so you convert that base 36 number to base 10, add 1 to it, then convert it back to base 36 and return it.
EDIT: Just realized that there may be an arbitrary string length of the code, but this approach might still be doable -- if you capture all the leading zeroes first, then strip them off, do the base 36 -> base 10 conversion, add one, and add back any needed leading zeroes ...
I would do something like this:
getNextChar($character) {
if ($character == '9') {
return 'A';
}
else if ($character == 'Z') {
return '0';
}
else {
return chr( ord($character) + 1);
}
}
getNextCode($code) {
// reverse, make into array
$codeRevArr = str_split(strrev($code));
foreach($codeRevArr as &$character) {
$character = getNextChar($character);
// keep going down the line if we're moving from 'Z' to '0'
if ($character != '0') {
break;
}
}
// array to string, then reverse again
$newCode = strrev(implode('', $codeRevArr));
return $newCode;
}
I was interested in the more general solution to this problem - i.e. dealing with arbitrary character sets in arbitrary orders. I found it easiest to first translate to alphabet indexes and back again.
function getNextAlphaNumeric($code, $alphabet) {
// convert to indexes
$n = strlen($code);
$trans = array();
for ($i = 0; $i < $n; $i++) {
$trans[$i] = array_search($code[$i], $alphabet);
}
// add 1 to rightmost pos
$trans[$n - 1]++;
// carry from right to left
$alphasize = count($alphabet);
for ($i = $n - 1; $i >= 0; $i--) {
if ($trans[$i] >= $alphasize) {
$trans[$i] = 0;
if ($i > 0) {
$trans[$i -1]++;
} else {
// overflow
}
}
}
// convert back
$out = str_repeat(' ', $n);
for ($i = 0; $i < $n; $i++) {
$out[$i] = $alphabet[$trans[$i]];
}
return $out;
}
$alphabet = array();
for ($i = ord('0'); $i <= ord('9'); $i++) {
$alphabet[] = chr($i);
}
for ($i = ord('A'); $i <= ord('Z'); $i++) {
$alphabet[] = chr($i);
}
echo getNextAlphaNumeric('009', $alphabet) . "\n";
echo getNextAlphaNumeric('00Z', $alphabet) . "\n";
echo getNextAlphaNumeric('0ZZ', $alphabet) . "\n";
<?php
define('ALPHA_ID_LENGTH', 3);
class AlphaNumericIdIncrementor {
// current id
protected $_id;
/**
* check if id is valid
*
* #param string $id
* #return bool
**/
protected static function _isValidId($id) {
if(strlen($id) > ALPHA_ID_LENGTH) {
return false;
}
if(!is_numeric(base_convert($id, 36, 10))) {
return false;
}
return true;
}
/**
* format $id
* fill with leading zeros and transform to uppercase
*
* #param string $id
* #return string
**/
protected static function _formatId($id) {
// fill with leading zeros
if(strlen($id) < ALPHA_ID_LENGTH) {
$zeros = '';
for($i = 0; $i < ALPHA_ID_LENGTH - strlen($id); $i++) {
$zeros .= '0';
}
$id = strtoupper($zeros . $id);
} else {
$id = strtoupper($id);
}
return $id;
}
/**
* construct
* set start id or null, if start with zero
*
* #param string $startId
* #return void
* #throws Exception
**/
public function __construct($startId = null) {
if(!is_null($startId)) {
if(self::_isValidId($startId)) {
$this->_id = $startId;
} else {
throw new Exception('invalid id');
}
} else {
$this->_generateId();
}
}
/**
* generate start id if start id is empty
*
* #return void
**/
protected function _generateId() {
$this->_id = self::_formatId(base_convert(0, 10, 36));
}
/**
* return the current id
*
* #return string
**/
public function getId() {
return $this->_id;
}
/**
* get next free id and increment $this->_id
*
* #return string
**/
public function getNextId() {
$this->_id = self::_formatId(base_convert(base_convert($this->_id, 36, 10) + 1, 10, 36));
return $this->_id;
}
}
$testId = new AlphaNumericIdIncrementor();
echo($testId->getId() . '<br />'); // 000
echo($testId->getNextId() . '<br />'); // 001
$testId2 = new AlphaNumericIdIncrementor('A03');
echo($testId2->getId() . '<br />'); // A03
echo($testId2->getNextId() . '<br />'); // A04
$testId3 = new AlphaNumericIdIncrementor('ABZ');
echo($testId3->getId() . '<br />'); // ABZ
echo($testId3->getNextId() . '<br />'); // AC0
?>
function formatPackageNumber($input)
{
//$input = $_GET['number'];
$alpha_array = array("A", "B" , "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");
$number_array = array("0", "1" , "2", "3", "4", "5", "6", "7", "8", "9");
$output = "";
for($i=0; $i<=5; $i++){
if($i>=4) {
$divisor = pow(26,$i-3)*pow(10,3);
} else {
$divisor = pow(10,$i);
}
$pos = floor($input/$divisor);
if($i>=3) {
$digit = $pos%26;
$output .= $alpha_array[$digit];
} else {
$digit = $pos%10 ;
$output .= $number_array[$digit];
}
}
return strrev($output);
}

Rewrite a large number of for loops into something shorter

I have the following code:
for($a=1; $a<strlen($string); $a++){
for($b=1; $a+$b<strlen($string); $b++){
for($c=1; $a+$b+$c<strlen($string); $c++){
for($d=1; $a+$b+$c+$d<strlen($string); $d++){
$tempString = substr_replace($string, ".", $a, 0);
$tempString = substr_replace($tempString, ".", $a+$b+1, 0);
$tempString = substr_replace($tempString, ".", $a+$b+$c+2, 0);
$tempString = substr_replace($tempString, ".", $a+$b+$c+$d+3, 0);
echo $tempString."</br>";
}
}
}
}
What it does is to make all possible combinatons of a string with several dots.
Example:
t.est123
te.st123
tes.t123
...
test12.3
Then, I add one more dot:
t.e.st123
t.es.t123
...
test1.2.3
Doing the way I'm doing now, I need to create lots and lots of for loops, each for a determined number of dots. I don't know how I can turn that example into a functon or other easier way of doing this.
Your problem is a combination problem. Note: I'm not a math freak, I only researched this information because of interest.
http://en.wikipedia.org/wiki/Combination#Number_of_k-combinations
Also known as n choose k. The Binomial coefficient is a function which gives you the number of combinations.
A function I found here: Calculate value of n choose k
function choose($n, $k) {
if ($k == 0) {return 1;}
return($n * choose($n - 1, $k - 1)) / $k;
}
// 6 positions between characters (test123), 4 dots
echo choose(6, 4); // 15 combinations
To get all combinations you also have to choose between different algorithms.
Good post: https://stackoverflow.com/a/127856/1948627
UPDATE:
I found a site with an algorithm in different programming languages. (But not PHP)
I've converted it to PHP:
function bitprint($u){
$s= [];
for($n= 0;$u > 0;++$n, $u>>= 1) {
if(($u & 1) > 0) $s[] = $n;
}
return $s;
}
function bitcount($u){
for($n= 0;$u > 0;++$n, $u&= ($u - 1));
return $n;
}
function comb($c, $n){
$s= [];
for($u= 0;$u < 1 << $n;$u++) {
if(bitcount($u) == $c) $s[] = bitprint($u);
}
return $s;
}
echo '<pre>';
print_r(comb(4, 6));
It outputs an array with all combinations (positions between the chars).
The next step is to replace the string with the dots:
$string = 'test123';
$sign = '.';
$combs = comb(4, 6);
// get all combinations (Th3lmuu90)
/*
$combs = [];
for($i=0; $i<strlen($string); $i++){
$combs = array_merge($combs, comb($i, strlen($string)-1));
}
*/
foreach ($combs as $comb) {
$a = $string;
for ($i = count($comb) - 1; $i >= 0; $i--) {
$a = substr_replace($a, $sign, $comb[$i] + 1, 0);
}
echo $a.'<br>';
}
// output:
t.e.s.t.123
t.e.s.t1.23
t.e.st.1.23
t.es.t.1.23
te.s.t.1.23
t.e.s.t12.3
t.e.st.12.3
t.es.t.12.3
te.s.t.12.3
t.e.st1.2.3
t.es.t1.2.3
te.s.t1.2.3
t.est.1.2.3
te.st.1.2.3
tes.t.1.2.3
This is quite an unusual question, but I can't help but try to wrap around what you are tying to do. My guess is that you want to see how many combinations of a string there are with a dot moving between characters, finally coming to rest right before the last character.
My understanding is you want a count and a printout of string similar to what you see here:
t.est
te.st
tes.t
t.es.t
te.s.t
t.e.s.t
count: 6
To facilitate this functionality I came up with a class, this way you could port it to other parts of code and it can handle multiple strings. The caveat here is the strings must be at least two characters and not contain a period. Here is the code for the class:
class DotCombos
{
public $combos;
private function combos($string)
{
$rebuilt = "";
$characters = str_split($string);
foreach($characters as $index => $char) {
if($index == 0 || $index == count($characters)) {
continue;
} else if(isset($characters[$index]) && $characters[$index] == ".") {
break;
} else {
$rebuilt = substr($string, 0, $index) . "." . substr($string, $index);
print("$rebuilt\n");
$this->combos++;
}
}
return $rebuilt;
}
public function allCombos($string)
{
if(strlen($string) < 2) {
return null;
}
$this->combos = 0;
for($i = 0; $i < count(str_split($string)) - 1; $i++) {
$string = $this->combos($string);
}
}
}
To make use of the class you would do this:
$combos = new DotCombos();
$combos->allCombos("test123");
print("Count: $combos->combos");
The output would be:
t.est123
te.st123
tes.t123
test.123
test1.23
test12.3
t.est12.3
te.st12.3
tes.t12.3
test.12.3
test1.2.3
t.est1.2.3
te.st1.2.3
tes.t1.2.3
test.1.2.3
t.est.1.2.3
te.st.1.2.3
tes.t.1.2.3
t.es.t.1.2.3
te.s.t.1.2.3
t.e.s.t.1.2.3
Count: 21
Hope that is what you are looking for (or at least helps)....

Validate IBAN PHP

As designing a new platform we tried to integrate the IBAN numbers. We have to make sure that the IBAN is validated and the IBAN stored to the database is always correct. So what would be a proper way to validate the number?
As the logic was explained in my other question, I've created a function myself. Based on the logic explained in the Wikipedia article find a proper function below. Country specific validation.
Algorithm and character lengths per country at https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN.
function checkIBAN($iban)
{
if(strlen($iban) < 5) return false;
$iban = strtolower(str_replace(' ','',$iban));
$Countries = array('al'=>28,'ad'=>24,'at'=>20,'az'=>28,'bh'=>22,'be'=>16,'ba'=>20,'br'=>29,'bg'=>22,'cr'=>21,'hr'=>21,'cy'=>28,'cz'=>24,'dk'=>18,'do'=>28,'ee'=>20,'fo'=>18,'fi'=>18,'fr'=>27,'ge'=>22,'de'=>22,'gi'=>23,'gr'=>27,'gl'=>18,'gt'=>28,'hu'=>28,'is'=>26,'ie'=>22,'il'=>23,'it'=>27,'jo'=>30,'kz'=>20,'kw'=>30,'lv'=>21,'lb'=>28,'li'=>21,'lt'=>20,'lu'=>20,'mk'=>19,'mt'=>31,'mr'=>27,'mu'=>30,'mc'=>27,'md'=>24,'me'=>22,'nl'=>18,'no'=>15,'pk'=>24,'ps'=>29,'pl'=>28,'pt'=>25,'qa'=>29,'ro'=>24,'sm'=>27,'sa'=>24,'rs'=>22,'sk'=>24,'si'=>19,'es'=>24,'se'=>24,'ch'=>21,'tn'=>24,'tr'=>26,'ae'=>23,'gb'=>22,'vg'=>24);
$Chars = array('a'=>10,'b'=>11,'c'=>12,'d'=>13,'e'=>14,'f'=>15,'g'=>16,'h'=>17,'i'=>18,'j'=>19,'k'=>20,'l'=>21,'m'=>22,'n'=>23,'o'=>24,'p'=>25,'q'=>26,'r'=>27,'s'=>28,'t'=>29,'u'=>30,'v'=>31,'w'=>32,'x'=>33,'y'=>34,'z'=>35);
if(array_key_exists(substr($iban,0,2), $Countries) && strlen($iban) == $Countries[substr($iban,0,2)]){
$MovedChar = substr($iban, 4).substr($iban,0,4);
$MovedCharArray = str_split($MovedChar);
$NewString = "";
foreach($MovedCharArray AS $key => $value){
if(!is_numeric($MovedCharArray[$key])){
if(!isset($Chars[$MovedCharArray[$key]])) return false;
$MovedCharArray[$key] = $Chars[$MovedCharArray[$key]];
}
$NewString .= $MovedCharArray[$key];
}
if(bcmod($NewString, '97') == 1)
{
return true;
}
}
return false;
}
Slight modification of #PeterFox answer including support for bcmod() when bcmath is not available,
<?php
function isValidIBAN ($iban) {
$iban = strtolower($iban);
$Countries = array(
'al'=>28,'ad'=>24,'at'=>20,'az'=>28,'bh'=>22,'be'=>16,'ba'=>20,'br'=>29,'bg'=>22,'cr'=>21,'hr'=>21,'cy'=>28,'cz'=>24,
'dk'=>18,'do'=>28,'ee'=>20,'fo'=>18,'fi'=>18,'fr'=>27,'ge'=>22,'de'=>22,'gi'=>23,'gr'=>27,'gl'=>18,'gt'=>28,'hu'=>28,
'is'=>26,'ie'=>22,'il'=>23,'it'=>27,'jo'=>30,'kz'=>20,'kw'=>30,'lv'=>21,'lb'=>28,'li'=>21,'lt'=>20,'lu'=>20,'mk'=>19,
'mt'=>31,'mr'=>27,'mu'=>30,'mc'=>27,'md'=>24,'me'=>22,'nl'=>18,'no'=>15,'pk'=>24,'ps'=>29,'pl'=>28,'pt'=>25,'qa'=>29,
'ro'=>24,'sm'=>27,'sa'=>24,'rs'=>22,'sk'=>24,'si'=>19,'es'=>24,'se'=>24,'ch'=>21,'tn'=>24,'tr'=>26,'ae'=>23,'gb'=>22,'vg'=>24
);
$Chars = array(
'a'=>10,'b'=>11,'c'=>12,'d'=>13,'e'=>14,'f'=>15,'g'=>16,'h'=>17,'i'=>18,'j'=>19,'k'=>20,'l'=>21,'m'=>22,
'n'=>23,'o'=>24,'p'=>25,'q'=>26,'r'=>27,'s'=>28,'t'=>29,'u'=>30,'v'=>31,'w'=>32,'x'=>33,'y'=>34,'z'=>35
);
if (strlen($iban) != $Countries[ substr($iban,0,2) ]) { return false; }
$MovedChar = substr($iban, 4) . substr($iban,0,4);
$MovedCharArray = str_split($MovedChar);
$NewString = "";
foreach ($MovedCharArray as $k => $v) {
if ( !is_numeric($MovedCharArray[$k]) ) {
$MovedCharArray[$k] = $Chars[$MovedCharArray[$k]];
}
$NewString .= $MovedCharArray[$k];
}
if (function_exists("bcmod")) { return bcmod($NewString, '97') == 1; }
// http://au2.php.net/manual/en/function.bcmod.php#38474
$x = $NewString; $y = "97";
$take = 5; $mod = "";
do {
$a = (int)$mod . substr($x, 0, $take);
$x = substr($x, $take);
$mod = $a % $y;
}
while (strlen($x));
return (int)$mod == 1;
}
The accepted answer is not the preferred way of validation. The specification dictates the following:
Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid
Replace the two check digits by 00 (e.g. GB00 for the UK)
Move the four initial characters to the end of the string
Replace the letters in the string with digits, expanding the string as necessary, such that A or a = 10, B or b = 11, and Z or z = 35. Each alphabetic character is therefore replaced by 2 digits
Convert the string to an integer (i.e. ignore leading zeroes)
Calculate mod-97 of the new number, which results in the remainder
Subtract the remainder from 98, and use the result for the two check digits. If the result is a single digit number, pad it with a leading 0 to make a two-digit number
I've written a class that validates, formats and parses strings according to the spec. Hope this helps some save the time required to roll their own.
The code can be found on GitHub here.
top rated function does NOT work.
Just try a string with '%' in it...
I'm using this one :
function checkIBAN($iban) {
// Normalize input (remove spaces and make upcase)
$iban = strtoupper(str_replace(' ', '', $iban));
if (preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$/', $iban)) {
$country = substr($iban, 0, 2);
$check = intval(substr($iban, 2, 2));
$account = substr($iban, 4);
// To numeric representation
$search = range('A','Z');
foreach (range(10,35) as $tmp)
$replace[]=strval($tmp);
$numstr=str_replace($search, $replace, $account.$country.'00');
// Calculate checksum
$checksum = intval(substr($numstr, 0, 1));
for ($pos = 1; $pos < strlen($numstr); $pos++) {
$checksum *= 10;
$checksum += intval(substr($numstr, $pos,1));
$checksum %= 97;
}
return ((98-$checksum) == $check);
} else
return false;
}
I found this solution in cakephp 3.7 validation class. Plain beautiful php realization.
/**
* Check that the input value has a valid International Bank Account Number IBAN syntax
* Requirements are uppercase, no whitespaces, max length 34, country code and checksum exist at right spots,
* body matches against checksum via Mod97-10 algorithm
*
* #param string $check The value to check
*
* #return bool Success
*/
public static function iban($check)
{
if (!preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$/', $check)) {
return false;
}
$country = substr($check, 0, 2);
$checkInt = intval(substr($check, 2, 2));
$account = substr($check, 4);
$search = range('A', 'Z');
$replace = [];
foreach (range(10, 35) as $tmp) {
$replace[] = strval($tmp);
}
$numStr = str_replace($search, $replace, $account . $country . '00');
$checksum = intval(substr($numStr, 0, 1));
$numStrLength = strlen($numStr);
for ($pos = 1; $pos < $numStrLength; $pos++) {
$checksum *= 10;
$checksum += intval(substr($numStr, $pos, 1));
$checksum %= 97;
}
return ((98 - $checksum) === $checkInt);
}
This function check the IBAN and need GMP activate http://php.net/manual/en/book.gmp.php.
function checkIban($string){
$to_check = substr($string, 4).substr($string, 0,4);
$converted = '';
for ($i = 0; $i < strlen($to_check); $i++){
$char = strtoupper($to_check[$i]);
if(preg_match('/[0-9A-Z]/',$char)){
if(!preg_match('/\d/',$char)){
$char = ord($char)-55;
}
$converted .= $char;
}
}
// prevent: "gmp_mod() $num1 is not an integer string" error
$converted = ltrim($converted, '0');
return strlen($converted) && gmp_strval(gmp_mod($converted, '97')) == 1;
}
enjoy !

Convert mixed fraction string to float in PHP

I assumed there'd be an easy way in PHP to convert a string like 18 5/16 into the float 18.3125. I can't find a straightforward function to do it. Is there one, or do I need to write my own?
I don't think such a function exists -- at least not bundled with PHP.
Writing a function that does this operation, if your string always have the same format, should not be too hard ; for example, I'd say that something like this should do the trick :
$str = '18 5/16';
var_dump(calc($str));
function calc($str) {
$int = 0;
$float = 0;
$parts = explode(' ', $str);
if (count($parts) >= 1) {
$int = $parts[0];
}
if (count($parts) >= 2) {
$float_str = $parts[1];
list($top, $bottom) = explode('/', $float_str);
$float = $top / $bottom;
}
return $int + $float;
}
Which will get you the following output :
float 18.3125
And you might get something shorter with a few regex ; something like this should do the trick, I suppose :
function calc($str) {
if (preg_match('#(\d+)\s+(\d+)/(\d+)#', $str, $m)) {
return $m[1] + $m[2] / $m[3];
}
return 0;
}
Else, not bundled in PHP, but already existing, maybe this class could help : Eval Math.
Disclaimer : I have not tested it -- so not quite sure it'll work in your specific situation.
To expand on Pascal's example, here is a more robust solution that can handle fractions greater than 1 and less than 1.
function parseFraction(string $fraction): float
{
if(preg_match('#(\d+)\s+(\d+)/(\d+)#', $fraction, $m)) {
return ($m[1] + $m[2] / $m[3]);
} else if( preg_match('#(\d+)/(\d+)#', $fraction, $m) ) {
return ($m[1] / $m[2]);
}
return (float)0;
}
Here is some basic test coverage, useful to integrate this code with phpunit
class FractionParserTest extends TestCase
{
/**
* < 1
* #return void
*/
public function testSimple(): void
{
$qty = '3/4';
$res = parseFraction($qty);
$this->assertEquals(0.75, $res);
}
/**
* > 1
* #return void
*/
public function testComplex(): void
{
$qty = '18 5/16';
$res = parseFraction($qty);
$this->assertEquals(18.3125, $res);
}
}

Categories