diff --git a/.gitignore b/.gitignore index 0670882..c5359c8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ vendor build .php_cs.cache +cache +!cache/.gitkeep diff --git a/cache/.gitkeep b/cache/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/examples/getMedias.php b/examples/getMedias.php new file mode 100644 index 0000000..b33f61b --- /dev/null +++ b/examples/getMedias.php @@ -0,0 +1,20 @@ +setUserName('pgrimaud'); + +/** @var \Instagram\Hydrator\Feed $feed */ +$feed = $api->getFeed(); + +foreach ($feed->getMedias() as $media) { + echo $media->getCaption() . "\n"; +} + +$api->setEndCursor($feed->getEndCursor()); +$feed = $api->getFeed(); + +foreach ($feed->getMedias() as $media) { + echo $media->getCaption() . "\n"; +} \ No newline at end of file diff --git a/src/Instagram/Api.php b/src/Instagram/Api.php index 4902c21..a53a234 100644 --- a/src/Instagram/Api.php +++ b/src/Instagram/Api.php @@ -5,6 +5,7 @@ use GuzzleHttp\Client; use Instagram\Exception\InstagramException; use Instagram\Transport\HTMLPage; +use Instagram\Transport\JsonFeed; class Api { @@ -13,6 +14,16 @@ class Api */ private $client = null; + /** + * @var string + */ + private $userName; + + /** + * @var string + */ + private $endCursor = null; + /** * Api constructor. * @param Client|null $client @@ -23,22 +34,42 @@ public function __construct(Client $client = null) } /** - * @param string $username * @return Hydrator\Feed * @throws InstagramException - * @throws \GuzzleHttp\Exception\GuzzleException */ - public function getFeed($username) + public function getFeed() { - if(empty($username)) { - throw new InstagramException('username cannot be empty'); + if (empty($this->userName)) { + throw new InstagramException('Username cannot be empty'); + } + + if ($this->endCursor) { + $feed = new JsonFeed($this->client, $this->endCursor); + } else { + $feed = new HTMLPage($this->client); } - $feed = new HTMLPage($this->client); - $hydrator = new Hydrator(); - $dataFetched = $feed->fetchData($username); + $dataFetched = $feed->fetchData($this->userName); + + $hydrator = new Hydrator(); $hydrator->setData($dataFetched); return $hydrator->getHydratedData(); } + + /** + * @param string $userName + */ + public function setUserName($userName) + { + $this->userName = $userName; + } + + /** + * @param string $endCursor + */ + public function setEndCursor($endCursor) + { + $this->endCursor = $endCursor; + } } diff --git a/src/Instagram/Exception/CacheException.php b/src/Instagram/Exception/CacheException.php new file mode 100644 index 0000000..78d2c6c --- /dev/null +++ b/src/Instagram/Exception/CacheException.php @@ -0,0 +1,7 @@ +generateFeed(); foreach ($this->data->edge_owner_to_timeline_media->edges as $edge) { - $node = $edge->node; + /** @var \stdClass $node */ + $node = $edge->node; + $media = new Media(); $media->setId($node->id); $media->setTypeName($node->__typename); - if($node->edge_media_to_caption->edges) { + if ($node->edge_media_to_caption->edges) { $media->setCaption($node->edge_media_to_caption->edges[0]->node->text); } @@ -78,6 +80,7 @@ private function generateFeed() $feed->setFollowers($this->data->edge_followed_by->count); $feed->setFollowing($this->data->edge_follow->count); $feed->setExternalUrl($this->data->external_url); + $feed->setEndCursor($this->data->edge_owner_to_timeline_media->page_info->end_cursor); return $feed; } diff --git a/src/Instagram/Hydrator/Feed.php b/src/Instagram/Hydrator/Feed.php index 04015d3..746481a 100644 --- a/src/Instagram/Hydrator/Feed.php +++ b/src/Instagram/Hydrator/Feed.php @@ -1,4 +1,5 @@ medias[] = $media; } + + /** + * @return string + */ + public function getEndCursor() + { + return $this->endCursor; + } + + /** + * @param string $endCursor + */ + public function setEndCursor($endCursor) + { + $this->endCursor = $endCursor; + } } diff --git a/src/Instagram/Hydrator/Media.php b/src/Instagram/Hydrator/Media.php index 14ddf38..16fe7af 100644 --- a/src/Instagram/Hydrator/Media.php +++ b/src/Instagram/Hydrator/Media.php @@ -1,4 +1,5 @@ rhxGis; + } + + /** + * @param string $rhxGis + */ + public function setRhxGis($rhxGis) + { + $this->rhxGis = $rhxGis; + } + + /** + * @return array + */ + public function getCookie() + { + return $this->cookie; + } + + /** + * @param array $cookie + */ + public function setCookie($cookie) + { + $this->cookie = $cookie; + } + + /** + * @return int + */ + public function getUserId() + { + return $this->userId; + } + + /** + * @param int $userId + */ + public function setUserId($userId) + { + $this->userId = $userId; + } +} diff --git a/src/Instagram/Storage/CacheManager.php b/src/Instagram/Storage/CacheManager.php new file mode 100644 index 0000000..9964481 --- /dev/null +++ b/src/Instagram/Storage/CacheManager.php @@ -0,0 +1,70 @@ +cacheDir = $cacheDir ?: $this->cacheDir; + } + + /** + * @param $userId + * @return string + */ + private function getCacheFile($userId) + { + return ($this->cacheDir ? $this->cacheDir : __DIR__ . '/../../../cache/') . $userId . '.cache'; + } + + /** + * @param $userId + * @return Cache|mixed + */ + public function getCache($userId) + { + if (is_file($this->getCacheFile($userId))) { + $handle = fopen($this->getCacheFile($userId), 'r'); + $data = fread($handle, filesize($this->getCacheFile($userId))); + $cache = unserialize($data); + + fclose($handle); + + if ($cache instanceof Cache) { + return $cache; + } + } + + return new Cache(); + } + + /** + * @param Cache $cache + * @param $userName + * @throws CacheException + */ + public function set(Cache $cache, $userName) + { + if (!is_writable(dirname($this->getCacheFile($userName)))) { + throw new CacheException('Cache folder is not writable'); + } + + $data = serialize($cache); + $handle = fopen($this->getCacheFile($userName), 'w+'); + + fwrite($handle, $data); + fclose($handle); + } +} diff --git a/src/Instagram/Transport/HTMLPage.php b/src/Instagram/Transport/HTMLPage.php index 6526322..4bfd67e 100644 --- a/src/Instagram/Transport/HTMLPage.php +++ b/src/Instagram/Transport/HTMLPage.php @@ -4,48 +4,61 @@ use GuzzleHttp\Client; use Instagram\Exception\InstagramException; +use Instagram\Storage\Cache; +use Instagram\Storage\CacheManager; -class HTMLPage +class HTMLPage extends Transport { - const INSTAGRAM_ENDPOINT = 'https://www.instagram.com/'; - - /** - * @var Client - */ - private $client; - /** * HTMLPage constructor. * @param Client $client */ public function __construct(Client $client) { - $this->client = $client; + parent::__construct($client); } /** - * @param string $userName + * @param $userName * @return mixed * @throws InstagramException * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \Instagram\Exception\CacheException */ public function fetchData($userName) { - $endpoint = self::INSTAGRAM_ENDPOINT . "$userName/"; + $endpoint = self::INSTAGRAM_ENDPOINT . $userName . '/'; + + $headers = [ + 'headers' => [ + 'user-agent' => self::USER_AGENT + ] + ]; - $res = $this->client->request('GET', $endpoint); + $res = $this->client->request('GET', $endpoint, $headers); $html = (string)$res->getBody(); + preg_match('/