Same name and namespace in other branches
  1. 4.7.x includes/unicode.inc \drupal_substr()
  2. 6.x includes/unicode.inc \drupal_substr()
  3. 7.x includes/unicode.inc \drupal_substr()

Cut off a piece of a string based on character indices and counts. Follows the same behaviour as PHP's own substr() function.

Note that for cutting off a string at a known character/substring location, the usage of PHP's normal strpos/substr is safe and much faster.

4 calls to drupal_substr()
blogapi_metaweblog_new_media_object in modules/blogapi/blogapi.module
Blogging API callback. Inserts a file into Drupal.
drupal_ucfirst in includes/unicode.inc
Capitalize the first letter of a UTF-8 string.
search_expand_cjk in modules/search/search.module
Basic CJK tokenizer. Simply splits a string into consecutive, overlapping sequences of characters ('minimum_word_size' long).
theme_username in includes/theme.inc
Format a username.

File

includes/unicode.inc, line 435

Code

function drupal_substr($text, $start, $length = NULL) {
  global $multibyte;
  if ($multibyte == UNICODE_MULTIBYTE) {
    return $length === NULL ? mb_substr($text, $start) : mb_substr($text, $start, $length);
  }
  else {
    $strlen = strlen($text);

    // Find the starting byte offset
    $bytes = 0;
    if ($start > 0) {

      // Count all the continuation bytes from the start until we have found
      // $start characters
      $bytes = -1;
      $chars = -1;
      while ($bytes < $strlen && $chars < $start) {
        $bytes++;
        $c = ord($text[$bytes]);
        if ($c < 0x80 || $c >= 0xc0) {
          $chars++;
        }
      }
    }
    else {
      if ($start < 0) {

        // Count all the continuation bytes from the end until we have found
        // abs($start) characters
        $start = abs($start);
        $bytes = $strlen;
        $chars = 0;
        while ($bytes > 0 && $chars < $start) {
          $bytes--;
          $c = ord($text[$bytes]);
          if ($c < 0x80 || $c >= 0xc0) {
            $chars++;
          }
        }
      }
    }
    $istart = $bytes;

    // Find the ending byte offset
    if ($length === NULL) {
      $bytes = $strlen - 1;
    }
    else {
      if ($length > 0) {

        // Count all the continuation bytes from the starting index until we have
        // found $length + 1 characters. Then backtrack one byte.
        $bytes = $istart;
        $chars = 0;
        while ($bytes < $strlen && $chars < $length) {
          $bytes++;
          $c = ord($text[$bytes]);
          if ($c < 0x80 || $c >= 0xc0) {
            $chars++;
          }
        }
        $bytes--;
      }
      else {
        if ($length < 0) {

          // Count all the continuation bytes from the end until we have found
          // abs($length) characters
          $length = abs($length);
          $bytes = $strlen - 1;
          $chars = 0;
          while ($bytes >= 0 && $chars < $length) {
            $c = ord($text[$bytes]);
            if ($c < 0x80 || $c >= 0xc0) {
              $chars++;
            }
            $bytes--;
          }
        }
      }
    }
    $iend = $bytes;
    return substr($text, $istart, max(0, $iend - $istart + 1));
  }
}