Skip to content

Instantly share code, notes, and snippets.

@ddimitrioglo
Last active October 6, 2016 15:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ddimitrioglo/dfe3b0f049567c3541ee97262d999470 to your computer and use it in GitHub Desktop.
Save ddimitrioglo/dfe3b0f049567c3541ee97262d999470 to your computer and use it in GitHub Desktop.
Since twitter has switched to streaming his API, we have to collect the data by ourselves. So I investigated a bit Tweeter's GNIP api and wrote a helper class. I hope it will be helpful for someone!
<?php
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
class TwitterGnipClient
{
const RULES_ENDPOINT = 'https://api.gnip.com...';
const STREAM_ENDPOINT = 'https://stream.gnip.com...';
/**
* @var string
*/
protected $user;
/**
* @var string
*/
protected $password;
/**
* @var HttpClient
*/
protected $httpClient;
/**
* TwitterGnipClient constructor.
* @param array $params
*/
public function __construct(array $params)
{
$this->user = $params['user'];
$this->password = $params['password'];
$this->httpClient = new HttpClient();
}
/**
* Auth username
* @return string
*/
protected function getUser()
{
return $this->user;
}
/**
* Auth password
* @return string
*/
protected function getPassword()
{
return $this->password;
}
/**
* Get Stream connection endpoint url
* @return string
*/
protected function getStreamUrl()
{
return self::STREAM_ENDPOINT;
}
/**
* Get rules endpoint url
* @return string
*/
protected function getRulesUrl()
{
return self::RULES_ENDPOINT;
}
/**
* Add rules to PowerTrack stream’s ruleset.
* @example ['id' => 'url', ...]
* @param array $data
*/
public function addRules(array $data)
{
$rules = [];
foreach ($data as $id => $url) {
$rules[] = $this->buildRuleForUrl($url, $id);
}
$this->httpClient->post($this->getRulesUrl(), [
'auth' => [$this->getUser(), $this->getPassword()],
'json' => ['rules' => $rules]
]);
}
/**
* Retrieves all existing rules for a stream.
* @return \Generator
*/
public function getRules()
{
$response = $this->httpClient->get($this->getRulesUrl(), [
'auth' => [$this->getUser(), $this->getPassword()]
]);
$batchStr = '';
$body = $response->getBody();
while (!$body->eof()) {
$batchStr .= $body->read(1024);
}
$batchArray = explode(PHP_EOL, $batchStr);
unset($batchStr);
foreach ($batchArray as $itemJson) {
yield $this->unpackJson($itemJson);
}
}
/**
* Removes the specified rules from the stream.
* @param $data
*/
public function deleteRules($data)
{
$rules = [];
foreach ($data as $id => $url) {
$rules[] = $this->buildRuleForUrl($url, $id);
}
$this->httpClient->delete($this->getRulesUrl(), [
'auth' => [$this->getUser(), $this->getPassword()],
'json' => ['rules' => array_values($rules)]
]);
}
/**
* Open stream through which the social data will be delivered.
* @return \Generator
*/
public function listenStream()
{
$response = $this->httpClient->get($this->getStreamUrl(), [
'auth' => [$this->getUser(), $this->getPassword()],
'stream' => true
]);
$batchStr = '';
$body = $response->getBody();
while (!$body->eof()) {
$batchStr .= $body->read(1024);
$batchArray = explode(PHP_EOL, $batchStr);
// leave the last piece of response as it can be incomplete
$batchStr = array_pop($batchArray);
foreach ($batchArray as $itemJson) {
yield $this->processBroadcastItem($this->unpackJson($itemJson));
}
}
$body->close();
}
/**
* Process broadcast item data
* @param $data
* @return array
*/
protected function processBroadcastItem($data)
{
if (is_array($data)) {
$url = str_replace('url_contains:', '', $data['gnip']['matching_rules'][0]['value']);
switch ($data['verb']) {
// Occurs when a user posts a new Tweet.
case 'post':
return $this->getMappedResponse($url, 'tweet', 1);
break;
// Occurs when a user Retweets another user's Tweet
case 'share':
return $this->getMappedResponse($url, 'retweet', $data['retweetCount']);
break;
}
}
return [];
}
/**
* Get mapped response
* @param string $url
* @param string $type
* @param int $value
* @return array
*/
protected function getMappedResponse($url, $type, $value)
{
$test = [
'url' => rtrim($url, '/'),
'tweets' => $type == 'tweet' ? (int) $value : 0,
'retweets' => $type == 'retweet' ? (int) $value : 0
];
return $test;
}
/**
* Build rule by url and tag
* @param string $url
* @param $tag
* @return array
*/
protected function buildRuleForUrl($url, $tag)
{
$ruleValue = preg_replace('/^https?:\/\//i', '', $url);
return [
'value' => sprintf('url_contains:%s', trim($ruleValue, '/')),
'tag' => (string) $tag
];
}
/**
* Get unpacked json
* @return mixed
*/
protected function unpackJson($json)
{
return json_decode($json, true);
}
/**
* Debug what request is sent over the wire.
* @example 'handler' => $this->requestDebugger()
* @return mixed
*/
private function requestDebugger()
{
$handler = $this->httpClient->getConfig('handler');
$middleware = Middleware::tap(function ($request) {
/** @var RequestInterface $request */
echo $request->getHeader('Content-Type');
});
return $middleware($handler);
}
}
@ddimitrioglo
Copy link
Author

Note that this helper woks with API v1.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment