src/libs/FullNameParser.php
public function parse_name($full_name)
	{

		# Remove leading/trailing whitespace
		$full_name = trim($full_name);

		// remove any words that don't add value
		// $full_name = str_replace("(Hons)", '', $full_name );
		// $full_name = str_replace("(hons)", '', $full_name );

		# Setup default vars
		extract(array('salutation' => '', 'fname' => '', 'initials' => '', 'lname' => '', 'lname_base' => '', 'lname_compound' => '', 'suffix' => ''));

		# Find all the professional suffixes possible
		$professional_suffix = $this->get_pro_suffix($full_name);

		// The position of the first professional suffix denotes the end of the name and the start of suffixes
		$first_suffix_index = mb_strlen($full_name);
		foreach ($professional_suffix as $key => $psx) {
			$start = mb_strpos($full_name, $psx);
			if ($start === FALSE) {
				echo "ASSERT ERROR, the professional suffix:" . $psx . " cannot be found in the full name:" . $full_name . "<br>";
				continue;
			}
			if ($start < $first_suffix_index) {
				$first_suffix_index = $start;
			}
		}

		// everything to the right of the first professional suffix is part of the suffix
		$suffix = mb_substr($full_name, $first_suffix_index);

		// remove the suffixes from the full_name
		$full_name = mb_substr($full_name, 0, $first_suffix_index);

		# Deal with nickname, push to array
		$has_nick = $this->get_nickname($full_name);
		if ($has_nick) {
			# Remove wrapper chars from around nickname
			$name['nickname'] = mb_substr($has_nick, 1, (mb_strlen($has_nick) - 2));
			# Remove the nickname from the full name
			$full_name = str_replace($has_nick, '', $full_name);
			# Get rid of consecutive spaces left by the removal
			$full_name = str_replace('  ', ' ', $full_name);
		}

		# Grab a list of words from the remainder of the full name
		$unfiltered_name_parts = $this->break_words($full_name);

		# Is first word a title or multiple titles consecutively?
		if (count($unfiltered_name_parts)) {
			// only start looking if there are any words left in the name to process
			while (count($unfiltered_name_parts) > 0 && $s = $this->is_salutation($unfiltered_name_parts[0])) {
				$salutation .= "$s ";
				array_shift($unfiltered_name_parts);
			}
			$salutation = trim($salutation);
			// Find if there is a line suffix, if so then move it out
			# Is last word a suffix or multiple suffixes consecutively?
			while (count($unfiltered_name_parts) > 0 && $s = $this->is_line_suffix($unfiltered_name_parts[count($unfiltered_name_parts) - 1], $full_name)) {
				if ($suffix != "") {
					$suffix = $s . ", " . $suffix;
				} else {
					$suffix .= $s;
				}
				array_pop($unfiltered_name_parts);
			}
			$suffix = trim($suffix);
		} else {
			$salutation = "";
			$suffix = "";
		}

		// Re-pack the unfiltered name parts array and exclude empty words
		$name_arr = array();
		foreach ($unfiltered_name_parts as $key => $name_part) {
			$name_part = trim($name_part);
			$name_part = rtrim($name_part, ',');
			if (mb_strlen($name_part) == '1') {
				// If any word left is of one character that is not alphabetic then it is not a real word, so remove it
				if (!$this->mb_ctype_alpha($name_part)) {
					$name_part = "";
				}
			}
			if (mb_strlen(trim($name_part))) {
				$name_arr[] = $name_part;
			}
		}
		$unfiltered_name_parts = $name_arr;

		# set the ending range after prefix/suffix trim
		$end = count($unfiltered_name_parts);

		# concat the first name
		for ($i = 0; $i < $end - 1; $i++) {
			$word = $unfiltered_name_parts[$i];
			# move on to parsing the last name if we find an indicator of a compound last name (Von, Van, etc)
			# we use $i != 0 to allow for rare cases where an indicator is actually the first name (like "Von Fabella")
			if ($this->is_compound($word) && $i != 0) {
				break;
			}
			# is it a middle initial or part of their first name?
			# if we start off with an initial, we'll call it the first name
			if ($this->is_initial($word)) {
				# is the initial the first word?
				if ($i == 0) {
					# if so, do a look-ahead to see if they go by their middle name
					# for ex: "R. Jason Smith" => "Jason Smith" & "R." is stored as an initial
					# but "R. J. Smith" => "R. Smith" and "J." is stored as an initial
					if ($this->is_initial($unfiltered_name_parts[$i + 1])) {
						$fname .= " " . mb_strtoupper($word);
					} else {
						$initials .= " " . mb_strtoupper($word);
					}
				} # otherwise, just go ahead and save the initial
				else {
					$initials .= " " . mb_strtoupper($word);
				}
			} else {
				$fname .= " " . $this->fix_case($word);
			}
		}

		if (count($unfiltered_name_parts)) {
			# check that we have more than 1 word in our string
			if ($end - 0 > 1) {
				# concat the last name and split last name in base and compound
				for ($i; $i < $end; $i++) {
					if ($this->is_compound($unfiltered_name_parts[$i])) {
						$lname_compound .= " " . $unfiltered_name_parts[$i];
					} else {
						$lname_base .= " " . $this->fix_case($unfiltered_name_parts[$i]);
					}
					$lname .= " " . $this->fix_case($unfiltered_name_parts[$i]);
				}
			} else {
				# otherwise, single word strings are assumed to be first names
				$fname = $this->fix_case($unfiltered_name_parts[$i]);
			}
		} else {
			$fname = "";
		}

		# return the various parts in an array
		$name['salutation'] = $salutation;
		$name['fname'] = trim($fname);
		$name['initials'] = trim($initials);
		$name['lname'] = trim($lname);
		$name['lname_base'] = trim($lname_base);
		$name['lname_compound'] = trim($lname_compound);
		$name['suffix'] = $suffix;
		return $name;
	}
public function parse_name($full_name)
	{

		# Remove leading/trailing whitespace
		$full_name = trim($full_name);

		// remove any words that don't add value
		// $full_name = str_replace("(Hons)", '', $full_name );
		// $full_name = str_replace("(hons)", '', $full_name );

		# Setup default vars
		extract(array('salutation' => '', 'fname' => '', 'initials' => '', 'lname' => '', 'lname_base' => '', 'lname_compound' => '', 'suffix' => ''));

		# Find all the professional suffixes possible
		$professional_suffix = $this->get_pro_suffix($full_name);

		// The position of the first professional suffix denotes the end of the name and the start of suffixes
		$first_suffix_index = mb_strlen($full_name);
		foreach ($professional_suffix as $key => $psx) {
			$start = mb_strpos($full_name, $psx);
			if ($start === FALSE) {
				echo "ASSERT ERROR, the professional suffix:" . $psx . " cannot be found in the full name:" . $full_name . "<br>";
				continue;
			}
			if ($start < $first_suffix_index) {
				$first_suffix_index = $start;
			}
		}

		// everything to the right of the first professional suffix is part of the suffix
		$suffix = mb_substr($full_name, $first_suffix_index);

		// remove the suffixes from the full_name
		$full_name = mb_substr($full_name, 0, $first_suffix_index);

		# Deal with nickname, push to array
		$has_nick = $this->get_nickname($full_name);
		if ($has_nick) {
			# Remove wrapper chars from around nickname
			$name['nickname'] = mb_substr($has_nick, 1, (mb_strlen($has_nick) - 2));
			# Remove the nickname from the full name
			$full_name = str_replace($has_nick, '', $full_name);
			# Get rid of consecutive spaces left by the removal
			$full_name = str_replace('  ', ' ', $full_name);
		}

		# Grab a list of words from the remainder of the full name
		$unfiltered_name_parts = $this->break_words($full_name);

		# Is first word a title or multiple titles consecutively?
		if (count($unfiltered_name_parts)) {
			// only start looking if there are any words left in the name to process
			while (count($unfiltered_name_parts) > 0 && $s = $this->is_salutation($unfiltered_name_parts[0])) {
				$salutation .= "$s ";
				array_shift($unfiltered_name_parts);
			}
			$salutation = trim($salutation);
			// Find if there is a line suffix, if so then move it out
			# Is last word a suffix or multiple suffixes consecutively?
			while (count($unfiltered_name_parts) > 0 && $s = $this->is_line_suffix($unfiltered_name_parts[count($unfiltered_name_parts) - 1], $full_name)) {
				if ($suffix != "") {
					$suffix = $s . ", " . $suffix;
				} else {
					$suffix .= $s;
				}
				array_pop($unfiltered_name_parts);
			}
			$suffix = trim($suffix);
		} else {
			$salutation = "";
			$suffix = "";
		}

		// Re-pack the unfiltered name parts array and exclude empty words
		$name_arr = array();
		foreach ($unfiltered_name_parts as $key => $name_part) {
			$name_part = trim($name_part);
			$name_part = rtrim($name_part, ',');
			if (mb_strlen($name_part) == '1') {
				// If any word left is of one character that is not alphabetic then it is not a real word, so remove it
				if (!$this->mb_ctype_alpha($name_part)) {
					$name_part = "";
				}
			}
			if (mb_strlen(trim($name_part))) {
				$name_arr[] = $name_part;
			}
		}
		$unfiltered_name_parts = $name_arr;

		# set the ending range after prefix/suffix trim
		$end = count($unfiltered_name_parts);

		# concat the first name
		for ($i = 0; $i < $end - 1; $i++) {
			$word = $unfiltered_name_parts[$i];
			# move on to parsing the last name if we find an indicator of a compound last name (Von, Van, etc)
			# we use $i != 0 to allow for rare cases where an indicator is actually the first name (like "Von Fabella")
			if ($this->is_compound($word) && $i != 0) {
				break;
			}
			# is it a middle initial or part of their first name?
			# if we start off with an initial, we'll call it the first name
			if ($this->is_initial($word)) {
				# is the initial the first word?
				if ($i == 0) {
					# if so, do a look-ahead to see if they go by their middle name
					# for ex: "R. Jason Smith" => "Jason Smith" & "R." is stored as an initial
					# but "R. J. Smith" => "R. Smith" and "J." is stored as an initial
					if ($this->is_initial($unfiltered_name_parts[$i + 1])) {
						$fname .= " " . mb_strtoupper($word);
					} else {
						$initials .= " " . mb_strtoupper($word);
					}
				} # otherwise, just go ahead and save the initial
				else {
					$initials .= " " . mb_strtoupper($word);
				}
			} else {
				$fname .= " " . $this->fix_case($word);
			}
		}

		if (count($unfiltered_name_parts)) {
			# check that we have more than 1 word in our string
			if ($end - 0 > 1) {
				# concat the last name and split last name in base and compound
				for ($i; $i < $end; $i++) {
					if ($this->is_compound($unfiltered_name_parts[$i])) {
						$lname_compound .= " " . $unfiltered_name_parts[$i];
					} else {
						$lname_base .= " " . $this->fix_case($unfiltered_name_parts[$i]);
					}
					$lname .= " " . $this->fix_case($unfiltered_name_parts[$i]);
				}
			} else {
				# otherwise, single word strings are assumed to be first names
				$fname = $this->fix_case($unfiltered_name_parts[$i]);
			}
		} else {
			$fname = "";
		}

		# return the various parts in an array
		$name['salutation'] = $salutation;
		$name['fname'] = trim($fname);
		$name['initials'] = trim($initials);
		$name['lname'] = trim($lname);
		$name['lname_base'] = trim($lname_base);
		$name['lname_compound'] = trim($lname_compound);
		$name['suffix'] = $suffix;
		return $name;
	}
This is the primary method which calls all other methods

@param string $name the full name you wish to parse
@return array returns associative array of name parts