Odyssey
hcuMIRhandler.i
1 <?php
2 /*
3  * FILE: hcuMIRhandler.i
4  * Functions to support examining and validating MIR packet data
5  */
6 
7 /**
8  * Check to see if given phone number matches regex
9  * @param $phone
10  * @return boolean true if $phone matches regex, otherwise false
11  */
12 function Match_Phone_Regex($phone) {
13  /*
14  * Validate that numbers match the North American Numbering Plan
15  * see https://en.wikipedia.org/wiki/North_American_Numbering_Plan
16  * Note - includes Carribean but NOT Mexico.
17  *
18  * This regex is matching against commonly used phone constructs, not checking for bizarre crap. This will match:
19  * 223 456 7890
20  * (223) 345-5555
21  * (323)344-4444
22  * 333-333-3333
23  * 2234567890
24  *
25  * also note! regex only matches full 10 digits.
26  * Returns false for 7-digit numbers missing area code
27  */
28  $regexPhone = '/(?:[2-9]\d{2}|\([2-9]\d{2}\))[ -]?[2-9]\d{2}[ -]?\d{4}/';
29 
30  if (preg_match($regexPhone, $phone)) {
31  return true;
32  }
33  return false;
34 }
35 
36 /**
37  * Given phone is sanitized to remove all non-digits
38  * If (sanitized) given phone contains exactly 7 or 10 digits,
39  * return formatted 123-1234 or 123-123-1234
40  *
41  * If (sanitized) given phone contains any other digit count,
42  * sanitized phone is returned unformatted.
43  *
44  * @param $phone
45  * @return string phone formatted as 123-4567 or 123-456-7890
46  *
47  */
48 function Format_Phone_Dashes($phone) {
49 
50  $phone = preg_replace("/[^0-9]/", "", $phone);
51  $length = strlen($phone);
52 
53  switch($length) {
54  case 7:
55  return preg_replace("/([0-9]{3})([0-9]{4})/", "$1-$2", $phone);
56 
57  case 10:
58  return preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "$1-$2-$3", $phone);
59 
60  default:
61  return $phone;
62  }
63  }
64 
65 
66  /**
67  * Check date as
68  * not empty
69  * valid content
70  * within requested range.
71  *
72  * @param string $datechk date to be checked
73  * @param string $datefmt desired display format
74  * @param string $mindate earliest acceptable date
75  * @param string $maxdate latest acceptable date
76  * @return string accepted date in requested format, or empty
77  */
78 
79  function Date_In_Range($datechk, $datefmt = 'Y-m-d', $mindate = '12/13/1901', $maxdate = '') {
80 
81  # set a timezone for strtotime
82  # validate chkdate is set, is convertable by strtotime, is within given range
83  date_default_timezone_set('UTC');
84 
85  $mindate = (!empty($mindate) && ($st = strtotime($mindate)) ? $st : strtotime('1901-12-31')); # default 12/31/1901
86  $maxdate = (!empty($maxdate) && ($st = strtotime($maxdate)) ? $st : time()); # default now
87  // $GLOBALS['HB_ENV']["SYSENV"]["logger"]->info( "Date_In_Range datechk $datechk datefmt $datefmt min $mindate max $maxdate st " . strtotime($datechk));
88 
89  if (!empty($datechk) && ($st = strtotime($datechk)) && $st > $mindate && $st < $maxdate) {
90  return date($datefmt, $st);
91  }
92 
93  return '';
94  }
95 
96 /*
97 * function FormatMIR inspects a provided mir['data'] packet returned from GetMemberInfo
98 * Sanitizes MIR data values, stripping whitespace, non-digits, etc
99 * Sets empty string for values that fail validation
100 * Email prefers HCU email
101 * strips whitespace,
102 * checks via validateEmail function
103 * State checks for ctype_alpha
104 * Zip strips space and dash, checks for all digits and length 5 or 9
105 * SSN strips space and dash, checks for all digits and length 9
106 * DOB via Date_In_Range function w/range 12/31/1901 - current date
107 * [HomePhone, WorkPhone, CellPhone, Fax] strips non-digits, checks for length 7 or 10
108 * ** Note ** use of Match_Phone_Regex function results in requiring 10 digits.
109 *
110 * Returns sanitized, formatted MIR
111 *
112 *
113 * @param array $MIR ['data'] section returned from GetMemberInfo
114 * @param string $Ml email value defined in HomeCU
115 * @param array $reqMIR array of values required by caller. Error if missing
116 * @param $datefmt string default 'Y-m-d' requested format for dates returned
117 * @param $phones string default 'flat' requested fromat for phone numbers [flat|split|named|shortname]
118 * @param $noEmpty default false when set will unset any empty $MIR values
119 * @param $BizFNdot default '' = no change;
120  'dot' will return '.' dot as firstname for business accts;
121  'pass' will remove firstname from reqMIR list of required elements
122 
123 * @return array sanitized $MIR
124 *
125 */
126 function FormatMIR($MIR, $Ml, $reqMIR, $datefmt = 'Y-m-d', $phones = 'flat', $noEmpty = false, $BizFNdot = '') {
127  try {
128 /*
129  // $mirFields = Array(
130  // "accountnumber",
131  // "firstname",
132  // "middlename",
133  // "lastname",
134  // "email",
135  // "homephone",
136  // "workphone",
137  // "cellphone",
138  // "fax",
139  // "ssn",
140  // "address1",
141  // "address2",
142  // "city",
143  // "state",
144  // "zip",
145  // "cc",
146  // "dob",
147  // "class"
148  // );
149 */
150 
151  $rmlist = array("#", "&", "/", "%", ",", ":", "=", "?", "'");
152 
153  # prefer HCU email, as it tends to be kept more current than core
154  $MIR['email'] = validateEmail($Ml) ? $Ml : HCU_array_key_value('email', $MIR);
155  /*
156  * Notice this does not reject an email with the $rmlist characters,
157  * just scrubs them out and keeps on truckin'
158  * Is that really what we want?
159  */
160  $MIR['email'] = str_replace($rmlist, "", $MIR['email']);
161 
162  if (!(HCU_array_key_value("email", $MIR) && ($MIR["email"] = preg_replace('/\s/', '', $MIR["email"])) &&
163  validateEmail($MIR["email"]) )) {
164  unset($MIR["email"]);
165  }
166 
167  $scrubs = [
168  'firstname',
169  'middlename',
170  'lastname',
171  'address1',
172  'address2',
173  'city',
174  'state',
175  'acountnumber',
176  'cc',
177  'class'
178  ];
179  foreach ($scrubs as $key) {
180  $MIR[$key] = str_replace($rmlist, "", HCU_array_key_value($key, $MIR));
181  }
182  # default country code to US. Assume CU will specify for other countries
183  if (trim($MIR['cc']) == '') {
184  $MIR['cc'] = 'US';
185  }
186 
187  if (trim($MIR['class']) == '') {
188  # Assume business class if lastname w/o firstname
189  # Some cores send business name as lastname w/empty firstname
190  # but can't (or don't) send class.
191 
192  # GetMemberInfo / _RetrieveMemberInfo sets default class
193  # to empty string if it is not set by the core.
194  if (trim($MIR['firstname']) == '' && trim($MIR['lastname']) <> '') {
195  $MIR['class'] = 'B';
196  } else {
197  $MIR['class'] = 'P'; # default to personal account
198  }
199  }
200  switch (strtolower($BizFNdot)) {
201  case 'dot':
202  # Some SSO partners require firstname / lastname even for business.
203  # If this is a business account with first name empty, lastname present
204  # and BizFNdot =='dot', fill firstname with a dot so we can connect
205  if (empty($MIR['firstname']) && !empty($MIR['lastname']) &&
206  in_array ( $MIR['class'] , array ('B','T') ) ) {
207  $MIR['firstname'] = '.';
208  }
209  break;
210  case 'pass':
211  # Some SSO allow empty firstname for business.
212  # If this is a business account with first name empty, lastname present
213  # and BizFNdot == 'pass', clear firstname from the 'required values' list
214  if (empty($MIR['firstname']) && !empty($MIR['lastname']) &&
215  in_array ( $MIR['class'] , array ('B','T') ) ) {
216  unset($reqMIR['firstname']);
217  }
218  break;
219  default:
220  # no action
221  }
222 
223  if (! (HCU_array_key_value("state", $MIR) && ctype_alpha($MIR["state"]))) {
224  $MIR['state'] = '';
225  }
226 
227  if (!(HCU_array_key_value("zip", $MIR) && ($MIR["zip"] = str_replace([" ","-"], '', $MIR["zip"])) &&
228  ctype_digit($MIR["zip"]) && in_array(strlen($MIR["zip"]),[5,9])) ) {
229  $MIR["zip"] = '';
230  }
231 
232  if (! (HCU_array_key_value("ssn", $MIR) &&
233  ($MIR["ssn"] = str_replace([" ","-"], '', $MIR["ssn"])) && ctype_digit($MIR["ssn"]) && strlen($MIR['ssn']) == 9) ){
234  $MIR["ssn"] = '';
235  }
236 
237  if ( ! HCU_array_key_value('dob', $MIR) ) {
238  $MIR["dob"] = "";
239  } else {
240  $MIR['dob'] = Date_In_Range(HCU_array_key_value('dob', $MIR), 'Y-m-d', '12/31/1901', time());
241  }
242  // $GLOBALS['HB_ENV']["SYSENV"]["logger"]->info( "After block DOB: " . HCU_array_key_value('dob', $MIR) . " .");
243 
244  $phoneorder = [
245  'homephone' => 'HomePhone',
246  'cellphone' => 'CellPhone',
247  'workphone' => 'WorkPhone',
248  'fax' => 'FaxNumber'
249  ];
250 
251  foreach ($phoneorder as $key => $name) {
252  # Warning... Match_Phone_Regex requires length 10
253  # not sure if this will be a problem or not
254  # leaving the length 7 code in place until we determine
255  # it is safe to remove
256  if (!(HCU_array_key_value($key, $MIR) && ($MIR[$key] = preg_replace('/\D/', '', $MIR[$key])) &&
257  in_array(strlen($MIR[$key]),[7,10]) && Match_Phone_Regex($MIR[$key])) ) {
258  unset($MIR[$key]);
259  }
260  }
261 
262  # fax included in the cleansing above,
263  # but not formatted or used to set a contact phone below
264  unset($phoneorder['fax']);
265 
266  if ($phones == 'flat') {
267  foreach($phoneorder as $key => $name) {
268  $MIR['phone'] = HCU_array_key_value($key, $MIR); # digits only
269  if (trim($MIR['phone']) != '') {
270  break;
271  }
272  }
273  } elseif ($phones == 'split') {
274  foreach($phoneorder as $key => $name) {
275  switch (strlen(HCU_array_key_value($key, $MIR))) {
276  case 10:
277  $MIR[$key] = [
278  'area' => substr($MIR[$key], 0, 3),
279  'pre' => substr($MIR[$key], 3, 3),
280  'num' => substr($MIR[$key], 6, 4)];
281  break;
282  case 7:
283  $MIR[$key] = [
284  'pre' => substr($MIR[$key], 0, 3),
285  'num' => substr($MIR[$key], 3, 4)];
286  break;
287  default:
288  unset($MIR[$key]);
289  break;
290  }
291  }
292  } elseif ($phones == 'named') {
293  $phoneorder = [
294  'homephone' => 'Home',
295  'cellphone' => 'Cell',
296  'workphone' => 'Work'
297  ];
298  $MIR['phonenumbers'] = [];
299 
300  foreach ($phoneorder as $key => $name) {
301  switch (strlen(HCU_array_key_value($key, $MIR))) {
302  case 10:
303  case 7:
304  $MIR['phonenumbers'][] = [
305  'number' => Format_Phone_Dashes($MIR[$key]),
306  'name' => $name
307  ];
308  break;
309 
310  default:
311  unset($MIR[$key]);
312  break;
313  }
314  }
315  } elseif ($phones == 'shortname') {
316  # shortname setting is for Allied
317  # shorter names, include isTextCapable, unset phonenumbers array if empty
318  $phoneorder = [
319  'homephone' => ['phname' => 'Home', 'isTextCapable' => false],
320  'cellphone' => ['phname' => 'Cell', 'isTextCapable' => true],
321  'workphone' => ['phname' => 'Work', 'isTextCapable' => false]
322  ];
323 
324  $MIR['phonenumbers'] = [];
325 
326  foreach ($phoneorder as $key => $settings) {
327  switch (strlen(HCU_array_key_value($key, $MIR))) {
328  case 10:
329  case 7:
330  $MIR['phonenumbers'][] = [
331  'number' => $MIR[$key],
332  'name' => $settings['phname'],
333  'isTextCapable' => $settings['isTextCapable']
334  ];
335  break;
336 
337  default:
338  unset($MIR[$key]);
339  break;
340  }
341  }
342  if (!count($MIR['phonenumbers'])) {
343  unset($MIR['phonenumbers']);
344  }
345 
346 
347  }
348 
349  if ($noEmpty) {
350  foreach(array_keys($MIR) as $key) {
351  if ( (is_array($MIR[$key]) && !count($MIR[$key])) ||
352  ( !is_array($MIR[$key]) && trim($MIR[$key]) == false) ) {
353  unset($MIR[$key]);
354  }
355  }
356  }
357 
358  $missing = array_diff_key($reqMIR, $MIR);
359  if (sizeof($missing)) {
360  throw new Exception("Incomplete Member Info (" . join(", ", array_keys($missing)) . ")");
361  }
362  $return['status']['response'] = true;
363  $return['status']['message'] = 'Success';
364  $return['data'] = $MIR;
365  } catch (Exception $e) {
366  $return['status']['response'] = false;
367  $return['status']['message'] = $e->getMessage();
368  $return['data'] = array();
369  }
370  return $return;
371 }
372 
373 ?>