Skip to content
This repository was archived by the owner on Jan 21, 2020. It is now read-only.

Commit bf2659e

Browse files
committed
Merge branch 'hotfix/280-characters'
Close #55
2 parents f79fe8c + abd27f0 commit bf2659e

File tree

4 files changed

+38
-24
lines changed

4 files changed

+38
-24
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
All notable changes to this project will be documented in this file, in reverse chronological order by release.
44

5-
## 3.0.2 - TBD
5+
## 3.0.2 - 2017-11-21
66

77
### Added
88

9-
- Nothing.
9+
- [#55](https://github.com/zendframework/ZendService_Twitter/pull/55) adds
10+
support for 280-character tweets.
1011

1112
### Changed
1213

TODO.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,3 @@ The following is a list of Twitter API methods not yet implemented:
7171
- users/suggestions
7272
- users/suggestions/:slug
7373
- users/suggestions/:slug/members
74-
75-
## Fixes/functionality updates
76-
77-
- Use `Normalizer` class to get normalized string, and then use that to count
78-
number of characters for purpose of string lengths.
79-
- Update allowed status length to 280 characters.

src/Twitter.php

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace ZendService\Twitter;
99

1010
use Closure;
11+
use Normalizer;
1112
use Traversable;
1213
use ZendOAuth as OAuth;
1314
use Zend\Http;
@@ -19,6 +20,15 @@
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
*/
2333
class 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'

test/TwitterTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,20 @@ public function testPostStatusUpdateToLongShouldThrowException()
485485
$twitter->statuses->update('Test Message - ' . str_repeat(' Hello ', 140));
486486
}
487487

488+
public function testStatusUpdateShouldAllow280CharactersOfUTF8Encoding()
489+
{
490+
$message = str_repeat('é', 280);
491+
$twitter = new Twitter\Twitter;
492+
$twitter->setHttpClient($this->stubOAuthClient(
493+
'statuses/update.json',
494+
Http\Request::METHOD_POST,
495+
'statuses.update.json',
496+
['status' => $message]
497+
));
498+
$response = $twitter->statuses->update($message);
499+
$this->assertInstanceOf(TwitterResponse::class, $response);
500+
}
501+
488502
public function testPostStatusUpdateEmptyShouldThrowException()
489503
{
490504
$this->expectException(Twitter\Exception\ExceptionInterface::class);

0 commit comments

Comments
 (0)