<?
/*
Common Phone Functions
function format($ph) # human formatted phone
function clean($ph) # COUNTRYCODE.PHONE
*/
class Phone
{
// Hardcoded. Sould not changes.
// Function to generate: Phone_PrefixAdmin::spreadPerSites()
const CODE_TO_SITE_MAP = [
RDSite::SITE_ID_PHONEOWNER_US => [201,206,210,212,214,216,218,225,229,234,239,253,254,270,281,302,303,305,308,315,316,318,319,320,321,325,330,337,340,346,347,352,360,361,385,386,401,402,404,405,407,409,419,423,425,430,432,435,440,456,469,470,478,500,502,504,505,507,509,512,513,515,516,518,521,522,523,524,525,526,527,528,529,531,532,533,535,538,539,542,543,544,545,546,547,549,550,551,552,553,554,556,558,561,563,566,567,569,575,577,578,580,585,588,589,600,603,605,606,607,609,612,614,615,620,622,631,633,641,644,646,651,655,671,677,678,682,684,688,700,701,702,706,710,712,713,716,718,719,720,725,727,731,732,737,740,754,762,763,770,772,775,785,786,800,801,806,808,813,817,822,830,832,833,844,845,848,850,855,856,859,862,863,865,866,877,880,881,882,883,884,885,886,887,888,889,900,901,903,904,907,908,912,913,914,915,917,918,929,931,936,937,940,941,952,954,956,970,972,973,979,985],
RDSite::SITE_ID_PHONEID_US => [202,203,204,205,207,208,209,213,215,217,219,224,226,228,231,236,240,242,246,248,249,250,251,252,256,260,262,263,264,267,268,269,272,276,284,289,301,304,306,307,309,310,312,313,314,317,323,331,334,336,339,343,345,351,354,365,367,368,382,387,403,406,408,410,412,413,414,415,416,417,418,424,428,431,434,437,438,441,442,443,450,458,460,468,473,474,475,479,480,484,501,503,506,508,510,514,517,519,520,530,534,540,541,548,559,562,570,571,573,574,579,581,584,586,587,601,602,604,608,610,613,616,617,618,619,623,626,630,636,639,647,649,650,657,660,661,662,664,667,669,670,672,681,683,703,704,705,707,708,709,714,715,717,721,724,734,742,747,753,757,758,760,765,767,769,773,774,778,779,780,781,782,784,787,802,803,804,805,807,809,810,812,814,815,816,818,819,825,828,831,843,847,857,858,860,864,867,868,869,870,872,873,876,878,879,902,905,906,909,910,916,919,920,925,928,938,939,942,947,949,951,971,978,980,984,989],
];
/**
* Returns formatted number. Makes some validation.
* IMPORTANT! Phone::format(2010000000) => (201)
* @param mixed $ph
* @return string
*/
PUBLIC static function format($ph) { # human formatted phone
$ph=preg_replace("![^\d]!","",$ph);
$pl=strlen($ph);
$p3=substr($ph,0,3);
if ($p3=='011' ) $ph=substr($ph,3);
if (substr($ph,0,2)=='00') $ph=substr($ph,2);
if ($ph[0]=='0') $ph=substr($ph,1);
$pl=strlen($ph);
if ($pl<5) return ""; // no junk phones
if ($pl<7) return substr($ph,0,-4)."-".substr($ph,-4);
switch($pl) {
case 7: return substr($ph,0,3)."-".substr($ph,3);
case 8:
# case 9: return substr($ph,0,-4)."-".substr($ph,-4);
case 10: return "(".substr($ph,0,3).") ".self::format(substr($ph,3));
}
return self::_international_phone_format($ph);
}
/**
* Formatted US phone, missing digits replaced with filler
* ex: (617) 372-51xx or (617) 372-xxxx
* @param mixed $phone_prefix string or int phone
* @param string $filler character to mask digits in partially showing phone
* @param string $format sprintf() format for phone output
* @return string phone number representation
*/
static function us($phone_prefix, $filler="*", $format=null) { # formatted US phone, missing digits replaced with $filler
if (!$format) {
$format = RDSite::sitePhoneFormat();
}
$phone_prefix = self::clean($phone_prefix);
if (!$phone_prefix) {
return "";
}
$p = substr($phone_prefix, 0, 1)=='1' ? substr($phone_prefix, 1) : $phone_prefix; # 10 digit US number
$l = strlen($p);
if ($l == 3) {
if (! $filler) {
//$ph = "($p)";
$ph = sprintf($format, $p, "", "");
$ph = preg_replace('!([^\d])([^\d]+)!i', "$1", $ph); // remove multiple
} else {
//$ph = "($p) ".str_repeat($filler, 3)."-".str_repeat($filler, 4);
$ph = sprintf($format, $p, str_repeat($filler, 3), str_repeat($filler, 4));
}
} else {
$addon = null;
if ($l>10) {
$addon = substr($p, 10);
$p = substr($p, 0, 10);
}
$ph = sprintf($format, substr($p, 0, 3), substr($p, 3, 3), substr($p, 6)) . cs(" #%d", $addon??0);
if ($filler && $l<10) {
return $ph.str_repeat($filler, 10-$l);
}
}
return $ph;
}
/**
* 3-digit US phone prefix from $phone
* @param string|int $phone
* @return int
* @example Phone::prefix3("1(800)1234-567");
*/
static function prefix3($phone) {
$phone = self::clean($phone);
return (int) (floor($phone / 10000000) - 1000);
}
/**
* 6-digit US phone prefix from $phone
* @param string|int $phone
* @return int
* @example Phone::prefix6("1(800)1234-567");
*/
static function prefix6($phone) {
$phone = self::clean($phone);
return (int) (floor($phone / 10000) - 1000000);
}
/*
Reasons:
rid => XXX - phone removal request
fl => XXX - removed for specific Name (FL)
pid+fl => XXX - removed for profile_id, fl
*/
static function isForbidden($phone) { # [reason_hash] | null
$p = Phone::clean($phone);
if (strlen($p)!=11)
return;
#if ($r = M_ForbiddenPhones::isForbidden($p))
# return $r;
if ($r = KRDB_Phone::isForbidden($p))
return $r;
// null
}
public static function mask_number($p, $c = '*', int $numberOfMask = 4) {
return substr($p, 0, -$numberOfMask) . str_repeat($c, $numberOfMask);
}
/**
* @param string|null $source
* @param int $numberOfMask
* @param string $pattern
* @param bool $startFromEnd
* @return string
*/
public static function phoneMaskByDirection(?string $source, int $numberOfMask = 3, string $pattern = '*', bool $startFromEnd = true): string
{
$strlen = \mb_strlen($source);
$phoneResult = '';
for ($len = 0; $len < $strlen; $len++) {
if ($startFromEnd) {
$phoneResult .= $len >= ($strlen - $numberOfMask) ? preg_replace('/[\d]/', $pattern, $source[$len]) : $source[$len];
} else {
$phoneResult .= $len <= $numberOfMask ? preg_replace('/[\d]/', $pattern, $source[$len]) : $source[$len];
}
}
return $phoneResult;
}
/**
* use to store phones in database
* trim prefixes: "+", "011", "00", remove non digits
* ph = [prefix]countrycode-phone
* @param string|int $ph
* @return false|string|string[]|null
*/
PUBLIC static function clean($ph) { # COUNTRYCODE.PHONE
if (! $ph)
return "";
$ph=trim($ph);
if(!isset($ph[0]))
return "";
$international = ($ph[0]=='+') || substr($ph,0,1)=='0';
$ph=preg_replace("![^\d]!","",$ph); //only numbers
if (substr($ph,0,2)=='00') return substr($ph,2);
if (substr($ph,0,3)=='011') return substr($ph,3);
if (!empty($ph[0]) && $ph[0]=='0') $ph=substr($ph,1);
if (! $international || "1" == substr($ph,0,1)) { //Non international or internation North America number
$len = strlen($ph);
if ($len > 10) {
if ("1" == substr($ph,0,1)) {
$ph = substr($ph, 0, 11); // remove ext
} else {
$ph = substr($ph, 0, 10); // remove ext
}
$len = strlen($ph);
}
if ($len == 10 && "1" != substr($ph,0,1)) {
$ph= (int) "1".$ph; // US NUMBER
}
}
return $ph;
}
// ================================================================================
// INTERNAL
static function _international_phone_format($ph) {
static $short_prefix=array(
20=>1,27=>1,
30=>1,31=>1,32=>1,33=>1,34=>1,36=>1,39=>1,
40=>1,41=>1,43=>1,44=>1,45=>1,46=>1,47=>1,48=>1,49=>1,
51=>1,52=>1,53=>1,54=>1,55=>1,56=>1,57=>1,58=>1,
60=>1,61=>1,62=>1,63=>1,64=>1,65=>1,66=>1,
76=>1,77=>1,
81=>1,82=>1,84=>1,86=>1,
90=>1,91=>1,92=>1,93=>1,94=>1,95=>1,98=>1,
);
static $long_prefix=array(
1242=>1,1246=>1,1264=>1,1268=>1,1284=>1,
1340=>1,1345=>1,1441=>1,1473=>1,
1649=>1,1664=>1,1670=>1,1671=>1,1684=>1,
1721=>1,1758=>1,1767=>1,1784=>1,1787=>1,
1808=>1,1809=>1,1829=>1,1849=>1,1868=>1,1869=>1,1876=>1,
1939=>1,
5399=>1,
7840=>1,7940=>1,
8810=>1,8811=>1,8812=>1,8813=>1,8816=>1,8817=>1,8818=>1,8819=>1);
if (isset($short_prefix[$ph[0].$ph[1]]) )
$p=2;
else
$p=3; // no 4d code support
if ($p==3 && $ph[0]=='7')
$p=1;
if ($p==3 && $ph[0]=='1')
$p=1;
if (isset($long_prefix[substr($ph,0,4)] ) )
$p=4;
$pref=substr($ph,0,$p);
$post=substr($ph,-4);
$ph=substr($ph,$p,-4);
$ph=substr($ph,0,-3)."-".substr($ph,-3);
if ($ph[0]=='-') $ph=substr($ph,1);
if ($pref=='1')
return "$ph-$post";
return "+$pref $ph-$post";
}
/*
'name' => 'Jennie Rodriguez',
'uk' => '1106769-20239:M1Data/90',
'bday' => '19800207',
'ethnic' => 'Hispanic',
'education' => 2,
'occupation' => 2,
'owner_rental' => 2,
'email' => 'jennierodriguez6@hotmail.com',
'_updated' => 1394238635,
'loc' =>
'street' => '428 e 137th st apt 4b',
'zip' => 10454,
'region' => 34,
'city' => 11,
'city_main' => 11,
'id' => 1,
'tp' => 'M1Data',
*/
static function p7_item($r, $phone, $mode = "ph_listing", bool $isPrettyWrap = false) {
switch (RDSite::siteID()) {
case RDSite::SITE_ID_NEWENGLANDFACTS_COM:
$cssClass = 'col small-24 medium-10 large-6 gray-text';
$cssClass2 = 'col small-24 medium-14 large-18';
$cssClass3 = "r text";
break;
case RDSite::SITE_ID_PHONEOWNER_US:
$cssClass = 'column small-24 medium-10 large-6 gray-text';
$cssClass2 = 'column small-24 medium-14 large-18';
$cssClass3 = "row text";
break;
default:
$cssClass = 'col-md-8 gray-text';
$cssClass2 = 'col-md-15';
$cssClass3 = "row text";
}
$l = $r['loc']??[];
$info = "";
$not_a_person = false;
switch ($r['tp']) {
case 'business':
//PFL2 "Avvo", "BBB", "HealthGrades", "Martindale", "Trulia", "Vitals", "Zillow"
if ($e = ($r["info"]['title']??""))
$info .= "<div class='$cssClass3'><div class='$cssClass'>Title:</div><div class='$cssClass2'>$e</div></div>";
if ($e = ($r["info"]['organization']??"")) {
if (!$r["name"]) {
$r["name"] = $e;
$not_a_person = true;
} elseif ($r["name"] != $e) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Organization:</div><div class='$cssClass2'>$e</div></div>";
}
}
if ($e = ($r["info"]['specialties']??[])) {
$e = array_slice($e, 0, 10, true);
$info .= "<div class='$cssClass3'><div class='$cssClass'>Specialties:</div><div class='$cssClass2'>".join(", ", $e)."</div></div>";
}
if (($r['src']??"") == 'HealthGrades') {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Type:</div><div class='$cssClass2'>Medical";
if ($t = ($r["info"]["suffix"]??"")) {
if (($r['src']??"") == 'HealthGrades') {
$t_str = Helper_MedicalAcronyms::short2long($t);
$info .= ", $t" . cs(" <span class='gray-text'>(%s)</span>", $t_str);
} else {
$info .= " $t";
}
}
$info .= "</div></div>";
}
if (($r['src']??"") == 'Avvo') {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Type:</div><div class='$cssClass2'>Lawyers</div></div>";
}
break;
case 'Shopclub':
case 'USBusiness':
case 'Org':
case 'Allareacodes':
if (!empty($r['email'])) {
if (\RDSite::SITE_ID_PHONEOWNER_US != Phone::codeToSite($phone) || "light_report" == $mode || "prefix_listing" == $mode || "crosspage_address_phone" == $mode || "crosspage_org_phone" == $mode || "crosspage_profile_phone" == $mode || "org-phone" == $mode) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Email:</div><div class='$cssClass2'>$r[email]</div></div>";
} else {
//$href2 = "https://".C(".radaris")."/report/reverse_phone_lookup?phone=".substr($phone,1);
$href2 = Phone::reversePhoneLookupReportUrl($phone, !CD("is_radaris")?true:C(".radaris"));
$info .= "<div class='$cssClass3'><div class='$cssClass'>Email:</div><div class='$cssClass2'><a rel=\"nofollow\" href=\"$href2\" >$r[email]</a></div></div>";
}
}
if ($e = ($r['title']??''))
$info .= "<div class='$cssClass3'><div class='$cssClass'>Title:</div><div class='$cssClass2'>$e</div></div>";
if ($e = ($r['organization']??'')) {
if (empty($r["name"])) {
$r["name"] = $e;
$not_a_person = true;
} elseif ($r["name"] != $e) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Organization:</div><div class='$cssClass2'>$e</div></div>";
}
}
if ($e = ($r['sic_name']??''))
$info .= "<div class='$cssClass3'><div class='$cssClass'>Specialties:</div><div class='$cssClass2'>$e</div></div>";
if ($e = ($r['industry']??'')){
if (is_array($e) ) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Industry:</div><div class='$cssClass2'>".cut(implode(", ", $e), 180)."</div></div>";
} else {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Industry:</div><div class='$cssClass2'>".cut($e, 180)."</div></div>";
}
}
if (isset($r["services"])) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Services:</div><div class='$cssClass2'>".cut(implode(", ", $r["services"]), 180)."</div></div>";
}
if (isset($r["categories"])) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Categories:</div><div class='$cssClass2'>".cut(implode(", ", $r["categories"]), 180)."</div></div>";
}
if (isset($r["products"])) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Products:</div><div class='$cssClass2'>".cut(implode(", ", $r["products"]), 180)."</div></div>";
}
$sites= [];
if (isset($r["sites"])) {
foreach($r["sites"] as $e){
$site_url = $e;
if (!starts_with($site_url, "http")) {
$site_url = "http://$site_url";
}
$site_host = preg_replace('`^www\.`i','',parse_url($site_url, PHP_URL_HOST));
if ("prefix_listing" == $mode) {
$sites[$site_host] = $site_host;
} else {
$sites[$site_host] = '<a rel="nofollow" href="'.$site_url.'">'.$site_host.'</a>';
}
}
}
if ($e = ($r["website"]??'')) {
$site_url = $e;
if (!starts_with($site_url, "http")) {
$site_url = "http://$site_url";
}
$site_host = preg_replace('`^www\.`i','',parse_url($site_url, PHP_URL_HOST));
if ("prefix_listing" == $mode) {
$sites[$site_host] = $site_host;
} else {
$sites[$site_host] = "<a rel=\"nofollow\" href=\"$site_url\">".$site_host."</a>";
}
}
if($sites){
$info .= "<div class='$cssClass3'><div class='$cssClass'>Site:</div><div class='$cssClass2'>".join(', ',$sites)."</div></div>";
}
break;
case 'M1Data':
if (!empty($r['email'])) {
if (\RDSite::SITE_ID_PHONEOWNER_US != Phone::codeToSite($phone) || "light_report" == $mode || "prefix_listing" == $mode || "crosspage_address_phone" == $mode || "crosspage_org_phone" == $mode || "crosspage_profile_phone" == $mode) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Email:</div><div class='$cssClass2'>$r[email]</div></div>";
} else {
$href2 = Phone::reversePhoneLookupReportUrl($phone, !CD("is_radaris")?true:C(".radaris"));
$info .= "<div class='$cssClass3'><div class='$cssClass'>Email:</div><div class='$cssClass2'><a rel=\"nofollow\" href=\"$href2\" >$r[email]</a></div></div>";
}
}
#if (1 == $r['owner_rental'])
# $info .= "Homeowner";
if ($e = ($r['occupation']??"")) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Occupation:</div><div class='$cssClass2'>".KRDB_PFL2_M1Data::$OCCUPATION[$e]."</div></div>";
}
if ($e = ($r['education']??"")) {
if ($e>0) {
$info .= "<div class='$cssClass3'><div class='$cssClass'>Education:</div><div class='$cssClass2'>".KRDB_PFL2_M1Data::$EDUCATION[$e]."</div></div>";
}
}
if ($e = ($r["bday"]??0)) {
$r["bday"] = str_replace("X", "0", $r["bday"]);
}
break;
}
if (!empty($r["name"]) && false !== strpos($r["name"], "&") || ($r['src']??"")=="BuildZoom" ) {
$not_a_person = true;
}
# $bday
$age = ($r['bday']??0) ? dt2age($r['bday']) : "";
$age = preg_replace("![^\d]!", "", $age);
$r['uk'] = preg_replace('!^(\d+-\d+)(-0:)!', "$1:", $r['uk']);
if ($not_a_person) {
if($r['tp'] == 'Org'){
if((RDSite::siteID() == RDSite::SITE_ID_PHONEOWNER_COM) && $r['src']=="BuildZoom" && $r['score']>30 && $org_id = fm('`^contractor:(\d+)`i', $r['uk'])){
$lnk = Contractor::url(['type'=>'contractor', 'id'=>$org_id]);
$a = "<a href=\""."https://".C(".homeflock")."$lnk\">$r[name]</a>";
}elseif(!RDSite::siteID() && "prefix_listing" != $mode && $org_id = fm('`^org:(\d+)`i', $r['uk'])){
$lnk = Org::profileUrl($org_id, $r['name']);
$a = "<a href=\""."https://".C(".business")."$lnk\">$r[name]</a>";
}else{
$a = "<span class=\"bus\">$r[name]</span>";
}
}else{
$a = "<span class=\"bus\">$r[name]</span>";
}
} else {
if ("prefix_listing" == $mode) {
} elseif ("phone_profile" == $mode || "light_report" == $mode ) {
list($fname_id, $lname_id) = HB::explode("-", substr($r['uk'], 0, strpos($r['uk'], ':')),2);
//30 Mar 2016 decided to lad to /people at phoneownre.com
$a = (!empty($r['no-pfl']) || empty($fname_id) || empty($lname_id))?($r['name']??""):'<a rel="nofollow" href="'.Phone::phonePeopleUrl($phone, HB::fl($fname_id,$lname_id), ($r['loc']??[])).'">' . ($r["name"]??"") .'</a>';
} else {
list($fname_id, $lname_id) = HB::explode("-", substr($r['uk'], 0, strpos($r['uk'], ':')),2);
if ($r['loc']['region'] ?? 0) {
if ($r['loc']['city_main'] ?? 0) {
$uk_loc = $r['loc']['region']."-".$r['loc']['city_main'];
} else {
$uk_loc = $r['loc']['region'];
}
} else {
$uk_loc = '-';
}
$uk = substr($r['uk'], 0, strpos($r['uk'], ':')).":".$uk_loc.cs(":%d",$age);
if(RDSite::siteID() == RDSite::SITE_ID_CENTEDA_COM || RDSite::siteID() == RDSite::SITE_ID_PERSONTRUST_COM){
$_url = '';
if($fname_id && $lname_id){
$names = Profile_Name::names([$fname_id,$lname_id]);
$_url = url("@search",['fname'=>$names[$fname_id], 'lname'=>$names[$lname_id]]);
}
$a = (!empty($r['no-pfl']) || empty($fname_id) || empty($lname_id))?($r['name']??""):'<a rel="nofollow" href="'.$_url."\">" . ($r["name"]??"") . "</a>";
}elseif(RDSite::siteID() == RDSite::SITE_ID_REHOLD){
//for checking profile in mantra on veripages
include_once("/rd/vhosts/rdc/veripages.com/lib/Name/Directory.php");
include_once("/rd/vhosts/rdc/veripages.com/lib/Helper/Sitemap.php");
if($r['name']) {
list($fname,$mname, $lname) = Profile_Name::get_name($r['name']);
$showUrlLink = false;
if(!empty($fname_id) && !empty($lname_id)) {
$fl = HB::fl($fname_id, $lname_id);
if (\Helper_Sitemap::isCurrentSiteFL($fl, \RDSite::SITE_ID_VERIPAGES_COM)) {
$showUrlLink = true;
}
}
$a = ( $showUrlLink == false || empty($fl) || !empty($r['no-pfl']) || empty($fname_id) || empty($lname_id)) ? ($r['name'] ?? "") : '<a rel="nofollow" href="https://' . C(".veripages") . "/name/$fname/$lname/\">" . ($r["name"] ?? "") . "</a>";
}
}else{
$a = (!empty($r['no-pfl']) || empty($fname_id) || empty($lname_id))?($r['name']??""):'<a rel="nofollow" href="https://'.C(".radaris")."/ng/search?flrc=$uk\">" . ($r["name"]??"") . "</a>";
}
}
}
if (Debug::is_admin()) {
if (!empty($r["_deleted"])) {
if (!empty($r["_forbidden"])) {
$a .= ' <span class="admin">forbidden: '.join(", ", $r["_forbidden"]).'</span>';
} else {
$a .= ' <span class="admin">deleted</span>';
}
}
$info .= "<div class=\"admin\" style=\"font-size:10px;border:0;color:red\">$r[uk]</div>";
}
if ("prefix_listing" == $mode || ($l && (!empty($l["po-box"]) || (!empty($l["street"]) && fm("!\bP\.? ?O\.? ?BOX\b(.*)!i", $l["street"]))))) {
$st = HB::locToPlainText($l);
} elseif ($l && (($l['street']??'') && (($l['city']??0) || ($l['city_main']??0)) && ($l['region']??0))) {
if ("phone_profile" == $mode || "light_report" == $mode) {
//30 Mar 2016 decided to lad to /people at phoneownre.com
if(RDSite::siteID() == RDSite::SITE_ID_CENTEDA_COM || RDSite::siteID() == RDSite::SITE_ID_PERSONTRUST_COM || RDSite::siteID() == RDSite::SITE_ID_RADARIS){
$st = '<span class="addr-cont">'.HB::locToPlainText($l).'</span>';
}else{
if (preg_match("!^(\d+)-(\d+):!iU", $r["uk"], $lfa)) {
$st = '<span class="addr-cont">'.HB::locToPlainText($l).'<a href="'.Phone::phoneAddressUrl($phone, HB::fl($lfa[1], $lfa[2]), $l).'" class="addr_link arrow" rel="nofollow">></a></span>';
} else {
$st = '<span class="addr-cont">'.HB::locToPlainText($l).'<a href="'.Phone::phoneAddressUrl($phone, 0, $l).'" class="addr_link arrow" rel="nofollow">></a></span>';
}
}
} else {
if (preg_match("!^(\d+)-(\d+):!iU", $r["uk"], $lfa)) {
$st = HB::loc2str($l, false, $lfa[1], $lfa[2], ($isPrettyWrap ? HB_Legacy::LINK_TYPE_WHOLE_LINE : true), false, $isPrettyWrap);
} else {
$st = HB::loc2str($l, false, 0, 0, ($isPrettyWrap ? HB_Legacy::LINK_TYPE_WHOLE_LINE : true), false, $isPrettyWrap);
}
}
} else {
$st = HB::locToPlainText($l);
// $st = ucwords(strtolower($l['street']));
}
return [ ['class="names"', $a], $st, $info ];
}
// prefix8(details) within prefix7
// when resolve_top_geo - resolved geo are provided instead of numbers
static function teaser7($prefix7, $resolve_top_geo=true, $only_full = false) { # [prefix8 => details]
Profiler::in("Phone::teaser7");
$p = substr(preg_replace("![^0-9]!", "", $prefix7), 0, 7);
$r = i("dt-phone")->select($p, ['phone7' => $p, 'phones>'.($only_full?1:0)], "phone8, phones, records, urecords, top_geo1, top_geo2, top_geo3, updated, has");
if ($resolve_top_geo) {
$rc = [];
foreach ($r as $row) {
list($region, $city) = self::_geo($row['top_geo1']);
if ($region && $region < 256 && $city)
$rc[]="$region-$city";
list($region, $city) = self::_geo($row['top_geo2']);
if ($region && $region < 256 && $city)
$rc[]="$region-$city";
list($region, $city) = self::_geo($row['top_geo3']);
if ($region && $region < 256 && $city)
$rc[]="$region-$city";
}
$rc2cs = $rc ? Geo_Go::go("cities", ["c" => join(",",$rc)]) : [];
foreach ($r as &$row) {
list($region, $city) = self::_geo($row['top_geo1']);
$row['top_geo1'] = $city ? $rc2cs["$region-$city"] : "";
list($region, $city) = self::_geo($row['top_geo2']);
$row['top_geo2'] = $city ? $rc2cs["$region-$city"] : "";
list($region, $city) = self::_geo($row['top_geo3']);
$row['top_geo3'] = $city ? $rc2cs["$region-$city"] : "";
}
}
Profiler::out();
return $r;
}
/**
* Prefix8 - international phone prefix - 8+ digits (int) from "1 (234) 567-8XXXX" and from "1 (234) 567-89XXX"
* use teaserResolveGeo call to resolve Geo
* @param int $prefix8
* @param bool $check_for_removed
* @param DB_Parallel|null $DB_Parallel
* @return array [ phone => [record1, record2, ...]]
*/
static function teaser8($prefix8, $check_for_removed = true, DB_Parallel &$DB_Parallel = null) {
$r = [];
Profiler::in("Phone::teaser8");
$r_cnt = 0;
$K = KRDB::i("phone", substr($prefix8, 0, 8), $DB_Parallel);
if (!$DB_Parallel || $DB_Parallel->isComplete()) {
$teaser = $K->items();
if (($pl = strlen($prefix8)) > 8) {
foreach ($teaser as $phone => $d) {
if (substr($phone, 0, $pl) == $prefix8) {
if (!empty($d["."]) && $check_for_removed) { // Check removed hashes. Only for 8+ phones to avoid heavy load.
$to_check = [];
foreach ($d["."] as $iid => $item) {
if (empty($item["_deleted"])) {
$tc = ["phone" => $phone];
if ($loc = ($item["loc"]??[])) {
$tc["loc"] = $loc;
}
if ($uk = ($item["uk"]??"")) {
$tc["uk"] = $uk;
}
$to_check[$iid] = $tc;
}
}
if ($removed = removal\Removal::filterRemoved($to_check, $d["."], "mark")) {
//Also save removals permanently
/* Permanent set may take a lot of time.
foreach ($removed as $iid => $tc) {
$K[$phone][$iid]->_deleted = $d["."][$iid]["_deleted"];
$K[$phone][$iid]->_forbidden = $d["."][$iid]["_forbidden"];
}
$K->save();
*/
}
} // Check removed hashes finished
$r[$phone] = $d;
}
}
$teaser = $r;
}
ksort($teaser);
$r = [];
$rc = [];
foreach ($teaser as $phone => $items_) {
$items = ($items_['.']??[]);
if ($items) {
foreach ($items as $k => & $i) {
if (!empty($i['email'])) {
$i['email'] = preg_replace("!^(.)(.+)\!(.+)!", '$1...@$3', $i['email']);
}
if (!empty($i['_deleted']) && !\Debug::is_admin()) {
unset($items[$k]);
}
}
if ($items) {
$r[$phone] = $items;
}
}
}
Profiler::out(['phones' => count($teaser)]);
} else {
Profiler::out();
}
return $r;
}
static function _geo($geo) { # [$r, $c]
return [$geo >> 16, $geo & 65535];
}
static function _geoName($geo) { # name
list($r,$c) = self::_geo($geo);
return Geo::name($r, $c);
}
// to use used on teaser8() data
// add city_state fields to "$phone/$nn/loc/city_state"
static function teaserResolveGeo(array $teaser) { # ['phone' => [ r1, r2, r3 ]]
$RC = []; // [r-c => 1]
foreach ($teaser as $phone => $items) {
foreach ($items as $item) {
$loc = $item['loc']??0;
if ($loc && ($loc['city']??0) && ($loc['region']??0)) {
$RC[$loc['region'] . "-" . $loc['city']] = 1;
}
}
}
if (! $RC)
return $teaser;
Profiler::in_off("- resolve geo");
$rc2cs = Geo_Go::go("cities", ["c" => join(",", array_keys($RC))]);
foreach ($teaser as &$items) {
foreach ($items as &$item) {
$loc = $item['loc']??0;
if ($loc && ($loc['city']??0) && ($loc['region']??0)) {
$rc = $loc['region'] . "-" . $loc['city'];
$item['loc']['city_state'] = $rc2cs[$rc];
}
}
unset($item);
}
unset($items);
Profiler::out(['phones' => count($teaser), 'cities' => count($RC)]);
return $teaser;
}
/**
* Build link to phone lookup report page
* @param string $phone
* @param mixed $absolute. if true - use C(".phones") domain, if string - use passed $absolute as domain
* @return string
*/
static function reversePhoneLookupReportUrl($phone, $absolute = true) {
$phone = Phone::clean($phone);
if (strlen($phone) > 11) {
$phone = substr($phone, 0, 11);
}
$url = "/report/reverse_phone_lookup?phone=$phone#findPhoneH";
if ($absolute) {
if ($absolute === true) {
switch (RDSite::siteID()) {
case RDSite::SITE_ID_PHONEID_US:
$domain = C(".phoneidus");
break;
case RDSite::SITE_ID_PHONEOWNER_US:
$domain = C(".phoneownerus");
break;
case RDSite::SITE_ID_PHONEOWNER_COM:
$domain = C(".phones");
break;
default:
$phone_site_id = Phone::codeToSite($phone);
if (RDSite::SITE_ID_PHONEOWNER_US == $phone_site_id) {
$domain = C(".phoneownerus");
} elseif (RDSite::SITE_ID_PHONEID_US == $phone_site_id) {
$domain = C(".phoneidus");
} else {
$domain = C(".phones");
}
break;
}
} else {
$domain = $absolute;
}
$url = "https://".$domain.$url;
}
return $url;
}
/**
* Builds phone profile page link
* @param string $phone
* @param bool $absolute
* @return string
*/
static function phonePrefixUrl($phone, $absolute = true) {
$ph = self::clean($phone);
if ($ph[0] == "1") {
$ph = substr($ph, 1);
}
$url = "/$ph";
$phone_site_id = Phone::codeToSite($phone);
if (RDSite::siteID() == RDSite::SITE_ID_PHONEOWNER_US || RDSite::siteID() == RDSite::SITE_ID_PHONEID_US) {
if (RDSite::siteID() != $phone_site_id) {
$url = "/ng$url";
}
}
if ($absolute) {
if ($absolute === true) {
switch (RDSite::siteID()) {
case RDSite::SITE_ID_PHONEID_US:
$domain = C(".phoneidus");
break;
case RDSite::SITE_ID_PHONEOWNER_US:
$domain = C(".phoneownerus");
break;
case RDSite::SITE_ID_PHONEOWNER_COM:
$domain = C(".phones");
break;
default:
$phone_site_id = Phone::codeToSite($phone);
if (RDSite::SITE_ID_PHONEOWNER_US == $phone_site_id) {
$domain = C(".phoneownerus");
} elseif (RDSite::SITE_ID_PHONEID_US == $phone_site_id) {
$domain = C(".phoneidus");
} else {
$domain = C(".phones");
}
break;
}
} else {
$domain = $absolute;
}
$url = "https://".$domain.$url;
}
return $url;
}
/**
* Builds link to prefix page but with # fraction to jump to phone in the listing
* @param string $phone
* @param bool $absolute
* @return string
*/
static function phoneAtPrefixPageUrl($phone, $absolute = true) {
$ph = self::clean($phone);
if ($ph[0] == "1") {
$ph = substr($ph, 1);
}
if (10 != strlen($ph)) {
$url = self::phonePrefixUrl($ph, $absolute);
} else {
$prefix = substr($ph, 0, 8);
$fraction = substr($ph, 8, 2);
$url = self::phonePrefixUrl($prefix, $absolute);
$url = $url . "#p$fraction";
}
return $url;
}
/**
* Builds phone profile page link
* @param string $phone
* @param bool $absolute
* @return string
*/
static function phoneProfileUrl($phone, $absolute = true) {
$ph = self::clean($phone);
if (strlen($ph) == 11 && $ph[0] == "1") {
$ph = substr($ph, 1);
}
$url = "/phone/$ph";
if ($absolute) {
if ($absolute === true) {
switch (RDSite::siteID()) {
case RDSite::SITE_ID_PHONEID_US:
$domain = C(".phoneidus");
break;
case RDSite::SITE_ID_PHONEOWNER_US:
$domain = C(".phoneownerus");
break;
case RDSite::SITE_ID_PHONEOWNER_COM:
$domain = C(".phones");
break;
default:
$phone_site_id = Phone::codeToSite($phone);
if (RDSite::SITE_ID_PHONEOWNER_US == $phone_site_id) {
$domain = C(".phoneownerus");
} elseif (RDSite::SITE_ID_PHONEID_US == $phone_site_id) {
$domain = C(".phoneidus");
} else {
$domain = C(".phones");
}
break;
}
} else {
$domain = $absolute;
}
$url = "https://".$domain.$url;
}
return $url;
}
/**
* Builds link to people page
* @param string $phone
* @param int $fl
* @param array $loc SH_Loc
* @param bool $absolute
* @return type
*/
static function phonePeopleUrl($phone, $fl, $loc, $absolute = false) {
$ph = self::clean($phone);
if (strlen($ph) == 11 && $ph[0] == "1") {
$ph = substr($ph, 1);
}
$fl = (int)$fl;
// $loc = Geo::parseLoc($loc);
$a = !empty($loc["region"])?HB::locToPlainText($loc):"";
$p = ["p" => $ph, "fl"=>$fl];
if ($a) {
$p["a"]=$a;
}
$site_id = RDSite::siteID();
if($fl && ($site_id == RDSite::SITE_ID_RADARIS || $site_id == RDSite::SITE_ID_CENTEDA_COM || $site_id == RDSite::SITE_ID_PERSONTRUST_COM) ){
list($fid,$lid) = HB::fl($fl);
if($fid && $lid){
$names = Profile_Name::names([$fid,$lid]);
if($site_id == RDSite::SITE_ID_CENTEDA_COM || $site_id == RDSite::SITE_ID_PERSONTRUST_COM){
$url = url("@search",['fname'=>$names[$fid], 'lname'=>$names[$lid]]);
}else{
$url = "/p/$names[$fid]/$names[$lid]/";
}
}else{
$url = '#';
}
}else{
$url = url("/ng/people", $p);
}
return $url;
}
/**
* Builds link to address page
* @param string $phone
* @param int $fl
* @param array $loc SH_Loc
* @param bool $absolute
* @return type
*/
static function phoneAddressUrl($phone, $fl, $loc, $absolute = false) {
$ph = self::clean($phone);
if (strlen($ph) == 11 && $ph[0] == "1") {
$ph = substr($ph, 1);
}
$fl = (int)$fl;
// $loc = Geo::parseLoc($loc);
$a = !empty($loc["region"])?HB::locToPlainText($loc):"";
$p = ["p" => $ph, "a"=>$a];
if ($fl) {
$p["fl"] = $fl;
}
$url = url("/ng/address", $p);
return $url;
}
/**
* Returns site ID for given phone/prefix
* @param string $phone
* @return int site ID
*/
static function codeToSite($phone) {
$site_id = RDSite::SITE_ID_PHONEOWNER_US; //default site for unmapped 3-digit prefixes
$prefix3 = self::clean($phone);
if ($prefix3) {
$prefix3 = substr($prefix3, 0, 1)=='1' ? substr($prefix3, 1, 3) : substr($prefix3, 0, 3);
}
foreach ([RDSite::SITE_ID_PHONEOWNER_US, RDSite::SITE_ID_PHONEID_US] as $sid) {
if (in_array($prefix3, self::CODE_TO_SITE_MAP[$sid])) {
$site_id = $sid;
break;
}
}
return $site_id;
}
/**
* Get list of phones interlinks.
* @param int $phone_for
* @param bool $check_for_removed
* @return array
* @throws Exception
*/
static function getInterlinks($phone_for, $check_for_removed = true) {
$phone = Phone::clean($phone_for);
if (strlen($phone) != 11) {
throw new Exception("Invalid phone number");
}
$prefix = substr($phone, 0, 8);
$P = KRDB::i("phone", $prefix);
$interlinks = ($P->interlinks[$phone]??0);
if ($interlinks && $check_for_removed) {
$to_check = [];
foreach ($interlinks as $phone => $interlink) {
$tc = ["phone" => $phone];
if ($loc = $interlink["loc"]) {
$tc["loc"] = $loc;
}
if ($uk = $interlink["uk"]) {
$tc["uk"] = $uk;
}
$to_check[$phone] = $tc;
}
if ($removed = removal\Removal::filterRemoved($to_check, $interlinks, "unset")) {
/* KRDB update may take a lot of time
self::setInterlinks($phone_for, $interlinks, true);
*/
}
}
return $interlinks;
}
/**
*
* @param int $phone_for
* @param array $intelinks
* @param bool $save_immediately
* @return array
* @throws Exception
*/
static function setInterlinks($phone_for, $intelinks, $save_immediately=true) {
$phone = Phone::clean($phone_for);
if (strlen($phone) != 11) {
throw new Exception("Invalid phone number");
}
$prefix = substr($phone, 0, 8);
$P = KRDB::i("phone", $prefix);
$orig_intelinks = $P->interlinks;
$orig_intelinks[$phone_for] = $intelinks;
$P->interlinks = $orig_intelinks;
if ($save_immediately) {
$P->save(true);
}
return ($P->interlinks[$phone]??0);
}
}