DOM ID encode PHP function

I needed to encode strings in a reversible way to be valid as XHTML IDs (letters, numbers, '-' and '_', must start with a letter). The following encode and decode functions do just that. If you are not using Drupal just replace drupal_substr() with your favourite multi-byte safe substr() function.


/**
 * Encode a string for use as a DOM id.
 * 
 * Replaces non-alphanumeric characters with an underscore and the hex representation of the character code
 * with letters in lowercase
 * NOTE: dechex() seems to lowercase by default but this is not specified in the documentation so avoid possible
 * cross platform issues we explicitly convert during encode
 * 
 * @see http://php.net/manual/en/function.dechex.php
 * @param UTF-8 string $id
 */
function domid_encode($id) {
  if (!empty($id)) {
    $encoded_id = preg_replace_callback(
      '/([^a-zA-Z0-9])/',
      function($matches) {
        return "_" . strtolower(dechex(ord($matches[0])));
      },
      $id
    );
    return 'I' . $encoded_id;
  }
}

/**
 * Decode a DOM id encoded by domid_encode().
 * 
 * @param UTF-8 string $encoded_id
 */
function domid_decode($encoded_id) {
  $encoded_id = drupal_substr($encoded_id, 1);
  if (!empty($encoded_id)) {
    $decoded_id = preg_replace_callback(
      '/_(.{2})/',
      function($matches) {
        return chr(hexdec(drupal_substr($matches[0], 1)));
      },
      $encoded_id
    );
  }
  return $decoded_id;
}