public function generateString($length, $characters = '')
    {
        if (is_int($characters)) {
            // Combine character sets
            $characters = $this->expandCharacterSets($characters);
        }
        if ($length == 0 || strlen($characters) == 1) {
            return '';
        } elseif (empty($characters)) {
            // Default to base 64
            $characters = $this->expandCharacterSets(self::CHAR_BASE64);
        }

        // determine how many bytes to generate
        // This is basically doing floor(log(strlen($characters)))
        // But it's fixed to work properly for all numbers
        $len   = strlen($characters);

        // The max call here fixes an issue where we under-generate in cases
        // where less than 8 bits are needed to represent $len
        $bytes = $length * ceil(($this->countBits($len)) / 8);

        // determine mask for valid characters
        $mask   = 256 - (256 % $len);

        $result = '';
        do {
            $rand = $this->generate($bytes);
            for ($i = 0; $i < $bytes; $i++) {
                if (ord($rand[$i]) >= $mask) {
                    continue;
                }
                $result .= $characters[ord($rand[$i]) % $len];
            }
        } while (strlen($result) < $length);
        // We may over-generate, since we always use the entire buffer
        return substr($result, 0, $length);
    }