You are here

biblio.contributors.inc in Bibliography Module 6.2

Functions related to contributors in Drupal biblio module.

File

includes/biblio.contributors.inc
View source
<?php

/**
 * @file
 * Functions related to contributors in Drupal biblio module.
 */

/**
 * Retrieves a biblio contributor object by contributor ID.
 *
 * // @todo: What happens if array or non-existant ID integer passed?
 * @param integer $cid
 *   Integer ID of a record in {biblio_contributor_data} table.
 *
 * @return object|?
 *   A contributor object if found; otherwise ??
 */
function biblio_get_contributor($cid) {
  static $contributor = array();
  if (!isset($contributor[$cid])) {
    $contributor[$cid] = db_fetch_object(db_query('SELECT * FROM {biblio_contributor_data} WHERE cid = %d', $cid));
  }
  return $contributor[$cid];
}

/**
 * Retrieves biblio contributor object based on exact match of contributor name.
 *
 * // @todo: What happens if array or non-existant name string passed?
 *
 * @param string $name
 *   Name of a contributor.
 *
 * @return object|?
 *   A contributor object if found; otherwise ??
 */
function biblio_get_contributor_by_name($name) {
  return db_fetch_object(db_query("SELECT * FROM {biblio_contributor_data} bcd WHERE bcd.name = '%s'", array(
    $name,
  )));
}

/**
 * Retrieves biblio contributor id based on exact match of contributor name.
 *
 * // @todo: What happens if array or non-existant name string passed?
 *
 * @param string $name
 *   Name of a contributor.
 *
 * @return int|null
 *   A contributor object if found; otherwise null
 */
function biblio_get_cid_by_name($name) {
  static $contributor = array();
  $cid = NULL;
  if (!isset($contributor[$name])) {
    $cid = db_result(db_query("SELECT cid FROM {biblio_contributor_data} bcd WHERE bcd.name = '%s'", array(
      $name,
    )));
    if (!$cid) {
      $cid = db_result(db_query("SELECT aka FROM {biblio_contributor_aka_data} bcad WHERE bcad.name = '%s'", array(
        $name,
      )));
    }
    if ($cid) {
      $contributor[$name] = $cid;
    }
  }
  return isset($contributor[$name]) ? $contributor[$name] : NULL;
}

/**
 * Retrieves first biblio contributor object based on node revision ID.
 *
 * // @todo: What happens if array or non-existant ID passed?
 *
 * @param integer $vid
 *   A node revision ID.
 *
 * @return object|?
 *   A contributor object if found; otherwise ??
 */
function biblio_get_first_contributor($vid) {
  static $contributor = array();
  if (!isset($contributor[$vid])) {
    $sql = "SELECT * " . "FROM {biblio_contributor} bc INNER JOIN {biblio_contributor_data} bcd ON bc.cid = bcd.cid " . "WHERE bc.vid = %d AND bc.rank = 0";
    $contributor[$vid] = db_fetch_object(db_query($sql, $vid));
  }
  return $contributor[$vid];
}

/**
 * Retrieves all biblio contributor objects associated with node revision ID.
 *
 * // @todo: What happens if array or non-existant ID passed?
 *
 * @param integer $vid
 *   A node revision ID.
 *
 * @return array
 *   A array of contributor objects if $vid found; otherwise empty array.
 */
function biblio_load_contributors($vid) {
  $contributors = array();

  // Do not change order of presentation of contributors.
  $sql = "SELECT * " . "FROM {biblio_contributor} bc INNER JOIN {biblio_contributor_data} bcd ON bc.cid = bcd.cid " . "WHERE bc.vid = %d " . "ORDER BY bc.rank ASC";
  $resource = db_query($sql, $vid);
  while ($creator = db_fetch_array($resource)) {
    $contributors[$creator['auth_category']][] = $creator;
  }
  return $contributors;
}

/**
 * Adds additional author named "et al" to the end of the author array.
 *
 * @param $authors -
 *   Array of author arrays to possibly augment.
 * @param integer $type
 *   Integer ID representing the author type.
 *
 * @return bool
 *   TRUE if author was added, FALSE if "et al" already present.
 */
function biblio_authors_add_etal(&$authors, $type) {
  $etal = "et al";
  $max_rank = 0;
  foreach ($authors as $author) {

    // et al author should be added only once per type
    if ($author['auth_type'] != $type) {
      continue;
    }
    if ($author['name'] == $etal) {
      return FALSE;
    }
    $max_rank = max($max_rank, $author['rank']);
  }
  $authors[] = biblio_parse_author(array(
    'name' => $etal,
    'auth_type' => $type,
    'lastname' => $etal,
    'rank' => $max_rank + 1,
  ));
  return true;
}

/**
 * Parses array of contributors and augments with additional information.
 *
 * @param array $contributors
 *   Array of contibutor arrays
 *
 * @return array|null
 *   An array of enhanced author arrays.
 */
function biblio_parse_contributors($contributors) {
  $result = array();
  if (count($contributors) < 1) {

    // @todo: Should something be returned here?
    return;
  }
  foreach ($contributors as $category => $authors) {
    $etal = array();
    foreach ($authors as $author) {

      // Remove any form of "et al" from name element for biblio_parse_author().
      $author_cleaned = preg_replace("/et\\.?\\s+al\\.?/", '', $author['name']);

      // If "et al" was present, store cleaned version for parsing.
      if ($author_cleaned != $author['name']) {
        $author['name'] = $author_cleaned;

        // Mark this author as "to be added" in $etal array
        $etal[$author['auth_type']] = TRUE;
      }
      $author['name'] = trim($author['name']);
      if (strlen($author['name'])) {
        $result[$category][] = biblio_parse_author($author, $category);
      }
    }

    // Add "et al" authors for all neccessary contrbutor categories
    foreach ($etal as $type => $dummy) {

      // Add "et al" only if plain authors exists.
      if (isset($result[$category])) {
        biblio_authors_add_etal($result[$category], $type);
      }
    }
  }
  return $result;
}

/**
 * Deletes all contributors associated with node ID.
 *
 * // @todo: Refactor to take a node ID or a node object?
 * // @todo: Shouldn't this return success?
 *
 * @param object $node
 *   A node object that contains a property 'nid'.
 *
 * @return null
 *   ? change to $success?
 */
function biblio_delete_contributors($node) {
  db_query('DELETE FROM {biblio_contributor} WHERE nid = %d', array(
    ':nid' => $node->nid,
  ));
  return;
}

/**
 * Deletes all contributors revisions associated with node revision ID.
 *
 * // @todo: Refactor to take a node revision ID or a node object?
 *
 * @param object $node
 *   A node object that contains a property 'vid'.
 *
 * @return integer
 *   Number of revisions deleted for supplied
 */
function biblio_delete_contributors_revision($node) {
  db_query('DELETE FROM {biblio_contributor} WHERE vid = %d', array(
    ':vid' => $node->vid,
  ));
  $count = db_affected_rows();
  return $count;
}

/**
 * Deletes a contributor based upon contributor ID.
 *
 * @param int $cid
 *   The ID of a contributor.
 *
 * @return integer
 *   The number of contributor records deleted for contributor ID.
 */
function biblio_delete_contributor($cid) {
  $count = 0;

  // @todo: Don't we want to delete x=ref data records first in case of failure
  //        in mid-process?
  db_query('DELETE FROM {biblio_contributor}
            WHERE cid = %d', array(
    ':cid' => $cid,
  ));
  db_query('DELETE FROM {biblio_contributor_data}
            WHERE cid = %d', array(
    ':cid' => $cid,
  ));
  $count = db_affected_rows();
  db_query('DELETE FROM {biblio_contributor_aka_data}
            WHERE aka = %d', array(
    ':cid' => $cid,
  ));
  return $count;
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function biblio_delete_contributor_revision($cid, $vid) {
  db_query('DELETE FROM {biblio_contributor}
            WHERE cid = %d and vid = %d', array(
    ':cid' => $cid,
    ':vid' => $vid,
  ));
  $count = db_affected_rows();
  return $count;
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function biblio_count_orphan_authors() {
  return db_result(db_query('SELECT COUNT(*) FROM {biblio_contributor_data} bcd WHERE bcd.cid NOT IN (SELECT DISTINCT(bc.cid) FROM {biblio_contributor} bc )'));
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function biblio_get_orphan_authors() {
  $authors = array();
  $result = db_query('SELECT distinct d.cid cid, name, affiliation
                         FROM {biblio_contributor_data} d
                         LEFT JOIN {biblio_contributor} c ON (d.cid=c.cid)
                         WHERE c.cid IS NULL');
  while ($author = db_fetch_array($result)) {
    $authors[] = $author;
  }
  return $authors;
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function biblio_delete_orphan_authors($force = FALSE) {
  if (variable_get('biblio_auto_orphaned_author_delete', 0) || $force) {
    $active_cids = array();
    $all_cids = array();
    $result = db_query('SELECT cid FROM {biblio_contributor} GROUP BY cid');
    while ($author = db_fetch_object($result)) {
      $active_cids[] = $author->cid;
    }
    $result = db_query('SELECT cid FROM {biblio_contributor_data} GROUP BY cid');
    while ($author = db_fetch_object($result)) {
      $all_cids[] = $author->cid;
    }
    $orphans = array_diff($all_cids, $active_cids);
    if (!empty($orphans)) {
      db_query('DELETE FROM {biblio_contributor_data} WHERE cid IN (' . implode(',', $orphans) . ')');
      $count = db_affected_rows();
      $message = t('%count orphaned authors were deleted from the biblio_contributor_data table.', array(
        '%count' => $count,
      ));
      watchdog('biblio_cron', $message);
    }
  }
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function biblio_insert_contributors($node) {
  if (empty($node->biblio_contributors)) {
    return true;
  }
  return _biblio_save_contributors($node->biblio_contributors, $node->nid, $node->vid);
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function biblio_update_contributors($node) {
  _biblio_save_contributors($node->biblio_contributors, $node->nid, $node->vid, TRUE);
  return;
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function biblio_save_contributor(&$author) {
  return drupal_write_record('biblio_contributor_data', $author);
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function biblio_update_contributor(&$author) {
  if (!isset($author['cid'])) {
    return false;
  }
  return drupal_write_record('biblio_contributor_data', $author, 'cid');
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function _biblio_contributor_sort(&$authors) {
  foreach ($authors as $key => $author) {
    if (!isset($author['rank']) || empty($author['rank'])) {
      $authors[$key]['rank'] = $key;
    }
  }
  usort($authors, '_biblio_contributor_usort');
}

/**
 *
 *
 * @param
 *
 *
 * @return
 *
 */
function _biblio_contributor_usort($a, $b) {
  if (empty($a['name'])) {
    return 1;
  }
  if (empty($b['name'])) {
    return -1;
  }
  return $a['rank'] < $b['rank'] ? -1 : 1;
}

/**
 * Save contributors to the database.
 *
 *
 *
 *
 * @param $contributors
 *
 * @param $nid
 *
 * @param $vid
 *
 * @param $update
 *   (optional) A logical flag indicating whether ...
 *
 * @return success of database operations
 *
 */
function _biblio_save_contributors(&$contributors, $nid, $vid, $update = FALSE) {
  module_load_include('php', 'biblio', 'includes/Parser');
  module_load_include('php', 'biblio', 'includes/Name');
  $rank = 0;
  db_query('DELETE FROM {biblio_contributor} WHERE nid = %d AND vid = %d', array(
    $nid,
    $vid,
  ));
  $name_parser = new HumanNameParser_Parser();
  if (is_array($contributors) && count($contributors)) {
    foreach ($contributors as $cat => $authors) {

      // Re-sort the authors by rank because the rank may have changed due to
      // javascript tabledrag on the input form.
      _biblio_contributor_sort($authors);
      foreach ($authors as $key => $author) {
        if (!empty($author['name'])) {
          if (isset($author['cid']) && !empty($author['cid'])) {

            // check to make sure the name wasn't changed
            // this should only happen via the node/add/biblio input form
            $auth = biblio_get_contributor($author['cid']);
            if (!empty($auth) && isset($auth->name) && $auth->name != $author['name']) {

              //if the name has changed, NULL the cid so a new entry is created
              $author['cid'] = NULL;
            }
            else {
              $contributors[$cat][$key] = array_merge($author, (array) $auth);
            }
          }

          // if we don't have a cid, lets see if we can find and exact match
          // to the name and use that cid
          if (!isset($author['cid']) || empty($author['cid'])) {
            $cid = biblio_get_cid_by_name($author['name']);
            if ($cid) {
              $author['cid'] = $cid;
              $contributors[$cat][$key]['cid'] = $cid;
            }
          }

          // if we still don't have a cid, then create a new entry in the biblio_contirbutor_data table
          if (empty($author['cid'])) {
            try {
              $author = $name_parser
                ->parseName($author);
            } catch (Exception $e) {
              $link = l('in node ' . $nid, 'node/' . $nid);
              $message = $e
                ->getMessage() . ' ' . $link;
              drupal_set_message($message, 'error');
              watchdog('biblio', $message, array(), WATCHDOG_ERROR);
            }
            $contributors[$cat][$key] = $author;
            biblio_save_contributor($author);
          }

          // we should now have a cid, if not we are in big trouble...
          if (empty($author['cid'])) {

            //throw error that author was not saved
          }
          $link_array = array(
            'nid' => $nid,
            'vid' => $vid,
            'cid' => $author['cid'],
            'rank' => $rank++,
            //((isset($author['rank']) && is_numeric($author['rank'])) ? $author['rank'] : $key),
            'auth_type' => $author['auth_type'],
            'auth_category' => $cat,
          );
          if (!drupal_write_record('biblio_contributor', $link_array)) {
            return FALSE;
          }
        }
      }
    }
  }
  db_query("UPDATE {biblio_contributor_data} SET aka = cid WHERE aka = 0 OR aka IS NULL");
  return TRUE;
}

/**
 * Parses an author name into its component parts.
 *
 * This function is partly based on a collection of PHP classes to manipulate
 * bibtex files and other work at http://bibliophile.sourceforge.net.
 *
 * That work was released through http://bibliophile.sourceforge.net under the
 * GPL licence. Do whatever you like with this -- some credit to the author(s)
 * would be appreciated. If you make improvements, please consider contacting
 * the administrators at bibliophile.sourceforge.net so that your improvements
 * can be added to the release package.
 *
 * Mark Grimshaw 2004/2005
 * http://bibliophile.sourceforge.net
 *
 * 28/04/2005 - Mark Grimshaw.
 * Efficiency improvements.
 *
 * 11/02/2006 - Daniel Reidsma.
 * Changes to preg_matching to account for Latex characters in names such as
 * {\"{o}}.
 *
 * @param string|array $contributor
 *   A string representing a name or an array with
 * @param $category_id
 *   (optional)
 *
 * @return array|false
 *   FALSE if there was an error; otherwise, an associative array for the parsed
 *   parts of a name, including at minimum the keys:
 *   - name:
 *   - firstname:
 *   - initials:
 *   - lastname:
 *   - prefix:
 *   - md5:
 */
function biblio_parse_author($contributor, $category_id = 0) {
  if (is_string($contributor)) {
    $author_array = array();
    $author_array['name'] = $contributor;
  }
  elseif (is_array($contributor) && isset($contributor['name'])) {
    $author_array = $contributor;
  }
  else {
    return FALSE;
  }
  if ($category_id == 5) {
    $author_array['firstname'] = '';
    $author_array['initials'] = '';
    $author_array['lastname'] = trim($author_array['name']);
    $author_array['prefix'] = '';

    // @todo: set suffix to empty string?
  }
  else {
    $value = trim($author_array['name']);
    $appellation = $prefix = $surname = $firstname = $initials = '';
    $prefix = "";
    $value = preg_replace("/\\s{2,}/", ' ', $value);

    // replace multiple white space by single space
    $author = explode(",", $value);
    $size = sizeof($author);

    // If only one element to author array, no commas were found.  Therefore,
    // the name is something like Mark Grimshaw | Mark Nicholas Grimshaw |
    // Mark N. Grimshaw | M N Grimshaw | or such.
    if ($size == 1) {

      // Is complete surname enclosed in {...}, unless the string starts with a backslash (\) because then it is
      // probably a special latex-sign..
      // 2006.02.11 DR: in the last case, any NESTED curly braces should also be taken into account! so second
      // clause rules out things such as author="a{\"{o}}"
      //
      if (preg_match("/(.*){([^\\\\].*)}/", $value, $matches) && !preg_match("/(.*){\\\\.{.*}.*}/", $value, $dummy)) {
        $author = explode(" ", $matches[1]);
        $surname = $matches[2];
      }
      else {
        $author = explode(" ", $value);

        // Last of element of array is surname (no prefix if entered correctly).
        $surname = array_pop($author);
      }
    }
    elseif ($size == 2) {

      // First element of array is surname (perhaps with a prefix).
      list($surname, $prefix) = _biblio_extract_surname_parts(array_shift($author));
    }
    else {

      // Middle element of array is 'Jr.', 'IV', etc.
      $appellation = implode(' ', array_splice($author, 1, 1));

      // First element of array is surname (perhaps with prefix).
      list($surname, $prefix) = _biblio_extract_surname_parts(array_shift($author));
    }
    $remainder = implode(" ", $author);
    list($firstname, $initials, $prefix2) = _biblio_extract_firstname_initials($remainder);
    if (!empty($prefix2)) {
      $prefix .= $prefix2;
    }
    $author_array['firstname'] = trim($firstname);
    $author_array['initials'] = trim($initials);
    $author_array['lastname'] = trim($surname);
    $author_array['prefix'] = trim($prefix);
    $author_array['suffix'] = trim($appellation);
  }
  $author_array['md5'] = biblio_calculate_contributor_hash($author_array);
  return $author_array;
}

/**
 * Creates an md5 hash string to ease contributor comparison logic.
 *
 * @param string|array $contributor
 *   A string with a name or array with one or more of the following elements,
 *   at least one of which is not empty:
 *   - firstname:
 *   - intiials:
 *   - prefix:
 *   - lastname:
 *
 * @return string
 *   An md5 hash string.
 */
function biblio_calculate_contributor_hash($contributor) {
  $hash = '';
  if (is_string($contributor)) {
    $creator = biblio_parse_author(array(
      'name' => trim($contributor),
    ));
  }
  elseif (is_array($contributor)) {
    $creator = $contributor;
  }
  else {
    return $hash;
  }
  $firstname = isset($creator['firstname']) ? $creator['firstname'] : '';
  $initials = isset($creator['initials']) ? $creator['initials'] : '';
  $prefix = isset($creator['prefix']) ? $creator['prefix'] : '';
  $lastname = isset($creator['lastname']) ? $creator['lastname'] : '';
  $string = $firstname . $initials . $prefix . $lastname;
  $string = str_replace(' ', '', drupal_strtolower($string));
  if (!empty($string)) {
    $hash = md5($string);
  }
  return $hash;
}

/**
 *
 *
 * grab firstname and initials which may be of form "A.B.C." or "A. B. C. " or " A B C " etc.
 *
 * @param $remainder
 *   The string representing the remainder of a name.
 *
 * @return array
 *   An array of three values: firstname, initials, prefix.
 */
function _biblio_extract_firstname_initials($remainder) {
  $prefix = array();
  $firstname = $initials = '';
  $array = explode(" ", $remainder);
  foreach ($array as $value) {
    $firstChar = drupal_substr($value, 0, 1);
    if (ord($firstChar) >= 97 && ord($firstChar) <= 122) {
      $prefix[] = $value;
    }
    elseif (preg_match("/[a-zA-Z]{2,}/", trim($value))) {
      $firstnameArray[] = trim($value);
    }
    else {
      $initialsArray[] = trim(str_replace(".", " ", trim($value)));
    }
  }
  if (isset($initialsArray)) {
    $initials = implode(" ", $initialsArray);
  }
  if (isset($firstnameArray)) {
    $firstname = implode(" ", $firstnameArray);
  }
  if (!empty($prefix)) {
    $prefix = implode(" ", $prefix);
  }
  return array(
    $firstname,
    $initials,
    $prefix,
  );
}

/**
 * Splits a surname string into its prefix and surname parts.
 *
 * A surname may have a title portion, such as 'den', 'von', 'de la', which are
 * characterised by a lowercased first character. Any uppercased part means
 * lowercased parts following are part of the surname (e.g. Van den Bussche).
 *
 * @param $input
 *   A string representing a name with a possible prefix.
 *
 * @return array
 *   An array with two elements representing surname and name prefix.
 */
function _biblio_extract_surname_parts($input) {
  $noPrefix = FALSE;
  $surname = FALSE;
  $prefix = FALSE;
  $surnameArray = explode(" ", $input);
  foreach ($surnameArray as $value) {
    $firstChar = substr($value, 0, 1);
    if (!$noPrefix && ord($firstChar) >= 97 && ord($firstChar) <= 122) {
      $prefix[] = $value;
    }
    else {
      $surname[] = $value;
      $noPrefix = TRUE;
    }
  }
  if (!empty($surname)) {
    $surname = implode(" ", $surname);
  }
  if (!empty($prefix)) {
    $prefix = implode(" ", $prefix);
  }
  return array(
    $surname,
    $prefix,
  );
}

/**
 * Returns array of md5 hash strings for all biblio contributors.
 *
 * // @todo: Is this function presently used anywhere?
 *
 * @return array|null
 *   An array of md5 hash values; otherwise null if no contributors.
 */
function _biblio_load_contributor_hashes() {
  static $md5 = array();
  static $count = 0;
  $db_count = db_result(db_query("SELECT COUNT(*) FROM {biblio_contributor_data}"));
  if ($db_count != $count) {
    $count = $db_count;
    $md5 = array();
    $result = db_query('SELECT md5,cid FROM {biblio_contributor_data}');
    while ($row = db_fetch_array($result)) {
      $md5[$row['cid']] = $row['md5'];
    }
  }
  return count($md5) ? $md5 : NULL;
}

/**
 * Retrieves a contributor ID value based on md5 hash value.
 *
 * // @todo: What is returned if no match found for md5 hash string?
 *
 * @param string $md5
 *   A md5 hash string.
 *
 * @return integer
 *   Integer ID of a contributor.
 */
function _biblio_get_cid_from_md5($md5) {
  $cid = db_result(db_query("SELECT cid FROM {biblio_contributor_data} WHERE md5='%s'", $md5));
  if (!$cid) {
    $cid = db_result(db_query("SELECT aka FROM {biblio_contributor_aka_data} WHERE md5='%s'", $md5));
  }
  return $cid;
}

/**
 *
 *
 * This function does what...
 *
 * @param object $user
 *   A user object with uid property.
 * @param object $node
 *   A node object.
 *
 * @return true|null
 *   TRUE if the user ID matches the author Drupal user ID; otherwsie NULL.
 */
function biblio_contributor_user_access($user, $node) {
  if (isset($node->biblio_contributors) && is_array($node->biblio_contributors)) {
    foreach ($node->biblio_contributors as $cat => $authors) {
      foreach ($authors as $key => $author) {
        if ($author['drupal_uid'] == $user->uid) {
          return TRUE;
        }
      }
    }
  }
  return;
}

Functions

Namesort descending Description
biblio_authors_add_etal Adds additional author named "et al" to the end of the author array.
biblio_calculate_contributor_hash Creates an md5 hash string to ease contributor comparison logic.
biblio_contributor_user_access This function does what...
biblio_count_orphan_authors
biblio_delete_contributor Deletes a contributor based upon contributor ID.
biblio_delete_contributors Deletes all contributors associated with node ID.
biblio_delete_contributors_revision Deletes all contributors revisions associated with node revision ID.
biblio_delete_contributor_revision
biblio_delete_orphan_authors
biblio_get_cid_by_name Retrieves biblio contributor id based on exact match of contributor name.
biblio_get_contributor Retrieves a biblio contributor object by contributor ID.
biblio_get_contributor_by_name Retrieves biblio contributor object based on exact match of contributor name.
biblio_get_first_contributor Retrieves first biblio contributor object based on node revision ID.
biblio_get_orphan_authors
biblio_insert_contributors
biblio_load_contributors Retrieves all biblio contributor objects associated with node revision ID.
biblio_parse_author Parses an author name into its component parts.
biblio_parse_contributors Parses array of contributors and augments with additional information.
biblio_save_contributor
biblio_update_contributor
biblio_update_contributors
_biblio_contributor_sort
_biblio_contributor_usort
_biblio_extract_firstname_initials grab firstname and initials which may be of form "A.B.C." or "A. B. C. " or " A B C " etc.
_biblio_extract_surname_parts Splits a surname string into its prefix and surname parts.
_biblio_get_cid_from_md5 Retrieves a contributor ID value based on md5 hash value.
_biblio_load_contributor_hashes Returns array of md5 hash strings for all biblio contributors.
_biblio_save_contributors Save contributors to the database.