I have in database product prices with 4 digits in decimal part, i.e;
4.5000
0.0050
5.0000
I want to show on the website these prices with minimum 2 decimal digits (without rounding), i.e;
4.50
0.005
5.00
I tried number_format, but it still leaves 4 digits in decimal part.
And also I need to use thousands separator on a base part of that number and own delimiter of decimal part.
How to do this?
function trimDecimalZero($num, $delim = ',', $tsep = ' ') {
#list($base, $decimals) = explode('.',
rtrim(number_format((float) $num, 4, '.', $tsep), '0'));
if (intval($decimals)) {
return sprintf('%s%s%s',
$base, $delim, strlen($decimals) < 2 ? $decimals .'0' : $decimals);
}
return sprintf('%s%s%02d', $base, $delim, $decimals);
}
$nums = [4.5000, 0.0050, 5.0000];
foreach ($nums as $num) {
var_dump(trimDecimalZero($num));
}
Result as expected;
string(4) "4,50"
string(5) "0,005"
string(4) "5,00"
Try with -
echo number_format('4.5000', 2);
Update
$v = (float)'0.0050';
$newV = explode('.', $v);
if(strlen($newV[1]) < 2) {
$v = number_format($v, 2);
}
echo $v;
For future reference, once again I modified my answer and yes, it outputs expected results:
function trimDecimalZero($number) {
$number += 0;
if(strlen(substr(strrchr($number, "."),1)) < 2) {
$number = sprintf("%0.2f", $number);
}
return $number;
}
echo trimDecimalZero(4.5000); //4.50
echo trimDecimalZero(0.00050); //0.00005
echo trimDecimalZero(5.0000); //5.00
Hope this would help future readers!
I guess that if it is for showing purposes, you could do something like this:
$number= 4.500000;
$number.= 'x';
$length = strlen($number);
$new_number = rtrim($number, '0x');
if (strlen($new_number) < $length) {
$new_number .= '0';
}
echo $new_number;
I have a large number that I want to split in half. For this example, let's use: 5639445604728832
When it is split in half it comes out like this:
56394456
04728832
Obviously, the second number isn't a number anymore.
I have the following code, but I am trying to make it so it will add the 0's to the end of the first number until the second number is officially a real number. Could anyone help me solve this?
function my_number_split($number)
{
$half = (int) ( (strlen($number) / 2) ); // cast to int incase str length is odd
$left = substr($number, 0, $half);
$right = substr($number, $half);
echo $left."<br />".$right;
}
Rewriting your function like this would do the trick.
function my_number_split($number)
{
$half = ceil( (strlen($number) / 2) );
while (0 == substr($number, $half, 1) && $half <= strlen($number) ) $half++;
$left = substr($number, 0, $half);
$right = substr($number, $half);
echo $left."<br />".$right;
}
Simple loop should do it.
Something like this -
function my_number_split($number)
{
/* Logic to traverse ahead till a 0 is not found. */
$str_len = strlen($number);
$half_index = $str_len/2;
while($half_index < $str_len){
if($number[$half_index] != "0"){
break;
}
$half_index++;
}
//Slicing string.
$left = substr($number, 0, $half_index);
$right = substr($number, $half_index);
echo $left."<br />".$right;
}
my_number_split("5639445604728832");
/*
OUTPUT -
563944560
4728832
*/
It's probably an inefficient way, but for the challenge:
if (preg_match('~\A(?<n1>.?(?:.(?=.*(.(?(2)\2)\z)))+0*)(?<n2>.+)~', $number, $m))
echo $m['n1'] . "\n" . $m['n2'];
I am building a simple friend/buddy system, and when someone tries to search for new friends, I want to show partially hidden email addresses, so as to give an idea about who the user might be, without revealing the actual details.
So I want abcdlkjlkjk#hotmail.com to become abcdl******#hotmail.com.
As a test I wrote:
<?php
$email = "abcdlkjlkjk#hotmail.com";
$em = explode("#",$email);
$name = $em[0];
$len = strlen($name);
$showLen = floor($len/2);
$str_arr = str_split($name);
for($ii=$showLen;$ii<$len;$ii++){
$str_arr[$ii] = '*';
}
$em[0] = implode('',$str_arr);
$new_name = implode('#',$em);
echo $new_name;
This works, but I was wondering if there was any easier/shorter way of applying the same logic? Like a regex maybe?
here's something quick:
function obfuscate_email($email)
{
$em = explode("#",$email);
$name = implode('#', array_slice($em, 0, count($em)-1));
$len = floor(strlen($name)/2);
return substr($name,0, $len) . str_repeat('*', $len) . "#" . end($em);
}
// to see in action:
$emails = ['"Abc\#def"#iana.org', 'abcdlkjlkjk#hotmail.com'];
foreach ($emails as $email)
{
echo obfuscate_email($email) . "\n";
}
echoes:
"Abc\*****#iana.org
abcdl*****#hotmail.com
uses substr() and str_repeat()
Maybe this is not what you want, but I would go for this:
<?php
/*
Here's the logic:
We want to show X numbers.
If length of STR is less than X, hide all.
Else replace the rest with *.
*/
function mask($str, $first, $last) {
$len = strlen($str);
$toShow = $first + $last;
return substr($str, 0, $len <= $toShow ? 0 : $first).str_repeat("*", $len - ($len <= $toShow ? 0 : $toShow)).substr($str, $len - $last, $len <= $toShow ? 0 : $last);
}
function mask_email($email) {
$mail_parts = explode("#", $email);
$domain_parts = explode('.', $mail_parts[1]);
$mail_parts[0] = mask($mail_parts[0], 2, 1); // show first 2 letters and last 1 letter
$domain_parts[0] = mask($domain_parts[0], 2, 1); // same here
$mail_parts[1] = implode('.', $domain_parts);
return implode("#", $mail_parts);
}
$emails = array(
'a#a.com',
'ab#aa.com',
'abc#aaa.com',
'abcd#aaaa.com',
'abcde#aaaaa.com',
'abcdef#aaaaaa.com',
'abcdefg#aaaaaaa.com',
'abcdefgh#aaaaaaaa.com',
'abcdefghi#aaaaaaaaa.com'
);
foreach ($emails as $email){
echo '<b>'.$email.'</b><br>'.mask_email($email).'<br><hr>';
}
Result:
a#a.com
*#*.com
ab#aa.com
**#**.com
abc#aaa.com
***#***.com
abcd#aaaa.com
ab*d#aa*a.com
abcde#aaaaa.com
ab**e#aa**a.com
abcdef#aaaaaa.com
ab***f#aa***a.com
abcdefg#aaaaaaa.com
ab****g#aa****a.com
abcdefgh#aaaaaaaa.com
ab*****h#aa*****a.com
abcdefghi#aaaaaaaaa.com
ab******i#aa******a.com
Here's my alternate solution for this.
I wouldn't use the exact number of mask characters to match the original length of the email, but rather use a fixed length mask for privacy reasons. I would also set the maximum allowed characters to show as well as never show more than half of the email. I would also mask all emails less than a minimum length.
With those rules in mind, here's my function with optional parameters:
function maskEmail($email, $minLength = 3, $maxLength = 10, $mask = "***") {
$atPos = strrpos($email, "#");
$name = substr($email, 0, $atPos);
$len = strlen($name);
$domain = substr($email, $atPos);
if (($len / 2) < $maxLength) $maxLength = ($len / 2);
$shortenedEmail = (($len > $minLength) ? substr($name, 0, $maxLength) : "");
return "{$shortenedEmail}{$mask}{$domain}";
}
Tests:
$email = "";
$tests = [];
for ($i=0; $i < 22; $i++) {
$email .= chr(97 + $i);
$tests[] = $email . " -> " . maskEmail("{$email}#example.com");
}
print_r($tests);
Results:
Array
(
[0] => a -> ***#example.com
[1] => ab -> ***#example.com
[2] => abc -> ***#example.com
[3] => abcd -> ab***#example.com
[4] => abcde -> ab***#example.com
[5] => abcdef -> abc***#example.com
[6] => abcdefg -> abc***#example.com
[7] => abcdefgh -> abcd***#example.com
[8] => abcdefghi -> abcd***#example.com
[9] => abcdefghij -> abcde***#example.com
[10] => abcdefghijk -> abcde***#example.com
[11] => abcdefghijkl -> abcdef***#example.com
[12] => abcdefghijklm -> abcdef***#example.com
[13] => abcdefghijklmn -> abcdefg***#example.com
[14] => abcdefghijklmno -> abcdefg***#example.com
[15] => abcdefghijklmnop -> abcdefgh***#example.com
[16] => abcdefghijklmnopq -> abcdefgh***#example.com
[17] => abcdefghijklmnopqr -> abcdefghi***#example.com
[18] => abcdefghijklmnopqrs -> abcdefghi***#example.com
[19] => abcdefghijklmnopqrst -> abcdefghij***#example.com
[20] => abcdefghijklmnopqrstu -> abcdefghij***#example.com
[21] => abcdefghijklmnopqrstuv -> abcdefghij***#example.com
)
For instance :
substr($email, 0, 3).'****'.substr($email, strpos($email, "#"));
Which will give you something like:
abc****#hotmail.com
I'm using this:
function secret_mail($email)
{
$prop=2;
$domain = substr(strrchr($email, "#"), 1);
$mailname=str_replace($domain,'',$email);
$name_l=strlen($mailname);
$domain_l=strlen($domain);
for($i=0;$i<=$name_l/$prop-1;$i++)
{
$start.='x';
}
for($i=0;$i<=$domain_l/$prop-1;$i++)
{
$end.='x';
}
return substr_replace($mailname, $start, 2, $name_l/$prop).substr_replace($domain, $end, 2, $domain_l/$prop);
}
Will output something like:
cyxxxxxone#gmxxxxcom
I created a function can help someone
function hideEmail($email)
{
$mail_parts = explode("#", $email);
$length = strlen($mail_parts[0]);
$show = floor($length/2);
$hide = $length - $show;
$replace = str_repeat("*", $hide);
return substr_replace ( $mail_parts[0] , $replace , $show, $hide ) . "#" . substr_replace($mail_parts[1], "**", 0, 2);
}
hideEmail("name#example.com"); // output: na**#**ample.com
hideEmail("something#example.com"); // output: some*****#**ample.com
You can customize as you want .. something like this (if length is 4 or less display only the first)
function hideEmail($email) {
$mail_parts = explode("#", $email);
$length = strlen($mail_parts[0]);
if($length <= 4 & $length > 1)
{
$show = 1;
}else{
$show = floor($length/2);
}
$hide = $length - $show;
$replace = str_repeat("*", $hide);
return substr_replace ( $mail_parts[0] , $replace , $show, $hide ) . "#" . substr_replace($mail_parts[1], "**", 0, 2);
}
hideEmail("name#example.com"); // output: n***#**ample.com
hideEmail("something#example.com"); // output: some*****#**ample.com
Very simple RegExp way:
$email = preg_replace('/\B[^#.]/', '*', $email)
Results:
john#smith.com: j***#s*****.c**
abcdef#example.org: a*****#e******.o**
abcdef: a*****
Sometimes its good to show the last character too.
ABCDEFZ#gmail.com becomes
A*****Z#gmail.com
I will suggest you keep things simple.
Maybe something like this is simple enough
https://github.com/fedmich/PHP_Codes/blob/master/mask_email.php
Masks an email to show first 3 characters and then the last character before the # sign
function mask_email( $email ) {
/*
Author: Fed
Simple way of masking emails
*/
$char_shown = 3;
$mail_parts = explode("#", $email);
$username = $mail_parts[0];
$len = strlen( $username );
if( $len <= $char_shown ){
return implode("#", $mail_parts );
}
//Logic: show asterisk in middle, but also show the last character before #
$mail_parts[0] = substr( $username, 0 , $char_shown )
. str_repeat("*", $len - $char_shown - 1 )
. substr( $username, $len - $char_shown + 2 , 1 )
;
return implode("#", $mail_parts );
}
I m using femich answer above and tweak it a bit for my
function mask_email($email, $char_shown_front = 1, $char_shown_back = 1)
{
$mail_parts = explode('#', $email);
$username = $mail_parts[0];
$len = strlen($username);
if ($len < $char_shown_front or $len < $char_shown_back) {
return implode('#', $mail_parts);
}
//Logic: show asterisk in middle, but also show the last character before #
$mail_parts[0] = substr($username, 0, $char_shown_front)
. str_repeat('*', $len - $char_shown_front - $char_shown_back)
. substr($username, $len - $char_shown_back, $char_shown_back);
return implode('#', $mail_parts);
}
test123#gmail.com -> t*****3#gmail.com
you can pass in the number of character to show in the front and in the back
You can also try this....
<?php
$email = "abcdlkjlkjk#hotmail.com";
$resultmob = substr($email,0,5);
$resultmob .= "**********";
$resultmob .= substr($email,strpos($email, "#"));
echo $resultmob;
?>
Answer:-
abcdl******#hotmail.com
Another variant that was heavily influenced by the answers already shared.
This has two key extra benefits:
It keeps the first characters after a defined set of delimiters, making it more readable while still preserving privacy.
It works with longer domain endings such as .org.uk and .com.au
Example: firstname.lastname#example.co.uk becomes f********.l*******#e*****.c*.u*
function mask_email( $email ) {
$masked = '';
$show_next = true;
foreach ( str_split( $email ) as $chr ) {
if ( $show_next ) {
$masked .= $chr;
$show_next = false;
}
else if ( in_array( $chr, array('.', '#', '+') ) ) {
$masked .= $chr;
$show_next = true;
}
else {
$masked .= '*';
$show_next = false;
}
}
return $masked;
}
Try this function. This will work with valid emails, such as "Abc\#def"#iana.org.
function hideEmail($email){
$prefix = substr($email, 0, strrpos($email, '#'));
$suffix = substr($email, strripos($email, '#'));
$len = floor(strlen($prefix)/2);
return substr($prefix, 0, $len) . str_repeat('*', $len) . $suffix;
}
echo hideEmail('abcdljtrsjtrsjlkjk#hotmail.com');
echo hideEmail('"abc\#def"#iana.org');
Returns
abcdljtrs*********#hotmail.com
"abc\*****#iana.org
I have a function
function hide_email($email){
$final_str = '';
$string = explode('#', $email);
$leftlength = strlen($string[0]);
$string2 = explode('.', $string[1]);
$string2len = strlen($string2[0]);
$leftlength_new = $leftlength-1;
$first_letter = substr($string[0], 0,1);
$stars = '';
$stars2 = '';
for ($i=0; $i < $leftlength_new; $i++) {
$stars .= '*';
}
for ($i=0; $i < $string2len; $i++) {
$stars2 .= '*';
}
$stars;
return $final_str .= $first_letter.$stars.'#'.$stars2.'.'.$string2[1];
}
echo hide_email('Hello#PHP.com');
There was an issue in case if there would be 1 character before #. I have fixed in below function.
function obfuscate_email($email)
{
$em = explode("#",$email);
if(strlen($em[0])==1){
return '*'.'#'.$em[1];
}
$name = implode(array_slice($em, 0, count($em)-1), '#');
$len = floor(strlen($name)/2);
return substr($name,0, $len) . str_repeat('*', $len) . "#" . end($em);
}
Here is version with only 2 lines (if you remove function stuff).
<?php
function censor_email($str,$amount=2, $char='*') {
list($local, $domain)=explode("#",$str);
return substr($local,0,$amount).str_repeat($char,strlen($local)-$amount)."#".$domain;
}
?>
function maskEmail($email) {
preg_match('/^.?(.*)?.#.+$/', $email, $matches);
return str_replace($matches[1], str_repeat('*', strlen($matches[1])), $email);
}
echo maskEmail('abcdefgh#example.com')
echo maskEmail('abh#example.com')
echo maskEmail('ah#example.com')
echo maskEmail('a#example.com')
returns
a******h#example.com
a*h#example.com
ah#example.com
a#example.com
This is what I did, as I required exact number of string count same as plain email.
This function only shows first & last two characters before "#"
function mask_email($email)
{
$em = explode("#",$email);
$len = strlen($em[0]);
$substr_count = 1;
if($len > 6)
$substr_count = 2;
$first = substr($em[0], 0,$substr_count);
$last = substr($em[0], -$substr_count);
$no_of_star = $len - ($substr_count * 2);
return $first.str_repeat('*', $no_of_star).$last."#".end($em);
}
Though this is an old thread & has many answers already. I want to share my own snippet too.
Which checks if it's a valid email or not.
How much characters to censor & to show.
What character should be used to censor.
function get_censored_email($email, $show_chars = 3, $censor_char = '*'){
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$char_length = strlen($email);
$censor_count = $char_length - $show_chars;
$return_email = substr($email, 0, $show_chars);
$return_email .= str_repeat("*", $censor_count);
return $return_email;
}
}
$email = 'noman.ibrahim115#gmail.com';
echo get_censored_email($email, 3, '*'); // returns nom***********************
Method 1:
<?php
function hideEmailAddress($email) {
if(filter_var($email, FILTER_VALIDATE_EMAIL)) {
list($first, $last) = explode('#', $email);
$first = str_replace(substr($first, '3'), str_repeat('*', strlen($first)-3), $first);
$last = explode('.', $last);
$last_domain = str_replace(substr($last['0'], '1'), str_repeat('*', strlen($last['0'])-1), $last['0']);
$hideEmailAddress = $first.'#'.$last_domain.'.'.$last['1'];
return $hideEmailAddress;
}
}
$email = "test#example.com";
echo hideEmailAddress($email);
?>
Method 2:
<?php
function hideEmailAddress($email) {
$em = explode("#",$email);
$name = implode(array_slice($em, 0, count($em)-1), '#');
$len = floor(strlen($name)/2);
return substr($name,0, $len) . str_repeat('*', $len) . "#" . end($em);
}
$email = 'test#example.com';
echo hideEmailAddress($email);
?>
What is the best way to add dashes to a phone number in PHP? I have a number in the format xxxxxxxxxx and I want it to be in the format xxx-xxx-xxxx. This only applies to 10 digit US phone numbers.
$number = "1234567890";
$formatted_number = preg_replace("/^(\d{3})(\d{3})(\d{4})$/", "$1-$2-$3", $number);
EDIT: To be a bit more generic and normalize a US phone number given in any of a variety of formats (which should be common practice - there's no reason to force people to type in a phone number in a specific format, since all you're interested in are the digits and you can simply discard the rest):
function localize_us_number($phone) {
$numbers_only = preg_replace("/[^\d]/", "", $phone);
return preg_replace("/^1?(\d{3})(\d{3})(\d{4})$/", "$1-$2-$3", $numbers_only);
}
echo localize_us_number("5551234567"), "\n";
echo localize_us_number("15551234567"), "\n";
echo localize_us_number("+15551234567"), "\n";
echo localize_us_number("(555) 123-4567"), "\n";
echo localize_us_number("+1 (555) 123-4567"), "\n";
echo localize_us_number("Phone: 555 1234567 or something"), "\n";
$number = '1234567890';
if(ctype_digit($number) && strlen($number) == 10) {
$number = substr($number, 0, 3) .'-'.
substr($number, 3, 3) .'-'.
substr($number, 6);
}
Or if you for some reason want to avoid substr:
$number = '1234567890';
if(ctype_digit($number) && strlen($number) == 10) {
$parts = str_split($number, 3);
$number = $parts[0] .'-'. $parts[1] .'-'. $parts[3].$parts[4];
}
iterate through the string and make counter. When counter is 3 or 7 insert dash.
I feel obliged to post. Cheesiest solution:
$number = "1234567890";
$formatted_number = "$number[0]$number[1]$number[2]-$number[3]$number[4]$number[5]-$number[6]$number[7]$number[8]$number[9]";
But it works and its fast. vs. the preg_replace solution:
250,000 iterations:
preg_replace: 1.23 seconds
ugly solution: 0.866 seconds
Pretty meaningless but fun :P
Here's what I used. It's not perfect, but it's an improvement over #Thilo's answer. It checks for a leading 1. If it's there, it ignores it. The code also ignores separating dashes, commas, and spaces, so it will work with 1231231234, 123 123 1234, and 123.123.1234. It doesn't handle numbers with parenthesis, but I'm sure there's another thread out there with that solution!
$formatted_number = preg_replace("/^1?(?:[- .])?(\d{3})(?:[- .])?(\d{3})(?:[- .])?(\d{4})$/", "($1) $2-$3", $not_formatted_phone_number);
A modification of Thilo's answer providing complete conditional formatting control over the leading "1".
public function phoneFormat($number) {
$numbersOnly = preg_replace("/[^\d]/", "", $number);
$nums = array_filter(explode("-", preg_replace("/^(1|)(\d{3})(\d{3})(\d{4})$/",
"$1-$2-$3-$4", $numbersOnly)));
$output = $numbersOnly;
if(count($nums) == 3){
$output = "($nums[1])-$nums[2]-$nums[3]";
}elseif(count($nums) == 4){
$output = "$nums[0]-($nums[1])-$nums[2]-$nums[3]";
}
return $output;
}
Here's what I came up with:
function format_phone($var_num) {
$var_num = trim($var_num);
$var_num = str_replace("(","",$var_num);
$var_num = str_replace(")","",$var_num);
$var_num = str_replace("-","",$var_num);
$var_num = str_replace(" ","",$var_num);
$var_num = str_replace(".","",$var_num);
$var_num = substr($var_num, -10);
$var_area_code = substr($var_num, 0, -7);
$var_exchange = substr($var_num, 3, -4);
$var_extention = substr($var_num, -4);
$var_return = "{$var_area_code}-{$var_exchange}-{$var_extention}";
return $var_return;
}
// Examples:
$phone_number = "1 (757) 555-1212";
// $phone_number = "17575551212";
// $phone_number = "(757) 555-1212";
// $phone_number = "757.555.1212";
echo "{$phone_number} = " . format_phone($phone_number);