88namespace ZendService \Twitter ;
99
1010use Closure ;
11+ use Normalizer ;
1112use Traversable ;
1213use ZendOAuth as OAuth ;
1314use Zend \Http ;
1920 *
2021 * Note: most `$id` parameters accept either string or integer values. This is
2122 * due to the fact that identifiers in the Twitter API may exceed PHP_INT_MAX.
23+ *
24+ * Note on character counting: Twitter accepts UTF-8 encoded text via the API,
25+ * and counts multi-byte characters as a single character. PHP's strlen(),
26+ * however, treats each byte as a character for purposes of determing the
27+ * string length. To get around that, we can pass the message to utf8_decode,
28+ * which will replace any multi-byte characters with a `?`; this works fine
29+ * for counting lengths.
30+ *
31+ * @see https://developer.twitter.com/en/docs/basics/counting-characters
2232 */
2333class Twitter
2434{
@@ -42,14 +52,9 @@ class Twitter
4252 ];
4353
4454 /**
45- * 246 is the current limit for a status message, 140 characters are displayed
46- * initially, with the remainder linked from the web UI or client. The limit is
47- * applied to a html encoded UTF-8 string (i.e. entities are counted in the limit
48- * which may appear unusual but is a security measure).
49- *
50- * This should be reviewed in the future...
55+ * As of November 2017, the character limit for status messages is 280.
5156 */
52- const STATUS_MAX_CHARACTERS = 246 ;
57+ const STATUS_MAX_CHARACTERS = 280 ;
5358
5459 /**
5560 * @var array
@@ -586,7 +591,7 @@ public function directMessagesEventsNew($user, string $text, array $extraParams
586591 {
587592 $ path = 'direct_messages/events/new ' ;
588593
589- $ len = iconv_strlen ( $ text, ' UTF-8 ' );
594+ $ len = strlen ( utf8_decode ( $ text) );
590595 if (0 === $ len ) {
591596 throw new Exception \InvalidArgumentException (
592597 'Direct message must contain at least one character '
@@ -980,7 +985,7 @@ public function searchTweets(string $query, array $options = []) : Response
980985 {
981986 $ path = 'search/tweets ' ;
982987
983- $ len = iconv_strlen ( $ query, ' UTF-8 ' );
988+ $ len = strlen ( utf8_decode ( $ query) );
984989 if (0 == $ len ) {
985990 throw new Exception \InvalidArgumentException (
986991 'Query must contain at least one character '
@@ -1260,13 +1265,13 @@ public function statusesShow($id, array $options = []) : Response
12601265 public function statusesUpdate (string $ status , $ inReplyToStatusId = null , $ extraAttributes = []) : Response
12611266 {
12621267 $ path = 'statuses/update ' ;
1263- $ len = iconv_strlen ( htmlspecialchars ($ status, ENT_QUOTES , ' UTF-8 ' ), ' UTF-8 ' );
1268+ $ len = strlen ( utf8_decode ($ status) );
12641269 if ($ len > self ::STATUS_MAX_CHARACTERS ) {
1265- throw new Exception \OutOfRangeException (
1266- 'Status must be no more than '
1267- . self ::STATUS_MAX_CHARACTERS
1268- . ' characters in length '
1269- );
1270+ throw new Exception \OutOfRangeException (sprintf (
1271+ 'Status must be no more than %d characters in length; received %d ' ,
1272+ self ::STATUS_MAX_CHARACTERS ,
1273+ $ len
1274+ )) ;
12701275 } elseif (0 == $ len ) {
12711276 throw new Exception \InvalidArgumentException (
12721277 'Status must contain at least one character '
@@ -1392,7 +1397,7 @@ public function usersSearch(string $query, array $options = []) : Response
13921397 {
13931398 $ path = 'users/search ' ;
13941399
1395- $ len = iconv_strlen ( $ query, ' UTF-8 ' );
1400+ $ len = strlen ( utf8_decode ( $ query) );
13961401 if (0 == $ len ) {
13971402 throw new Exception \InvalidArgumentException (
13981403 'Query must contain at least one character '
0 commit comments