Hi, today I’ll show you how to work with Github API in PHP.

At first let’s describe our goal: The script will extract a list of repositories using given language (e.g. Swift or Objective-C) and then get the properties like the owner, contributors and forks or watch counts for each repo and return neat JSON.

Required data structure:

REPOSITORY

  • id
  • name
  • full name
  • description
  • html url
  • owner_id
  • star_count
  • watching_count
  • fork_count
    USER

  • login

  • id
  • avatar_url
  • url
  • html_url
    CONTRIBUTORS

  • user_id

  • repo_id
  • number of contributions

Working with Github API

According to https://developer.github.com/v3/ API works as follows:

All API access is over HTTPS, and accessed from the api.github.com domain (or through yourdomain.com/api/v3/ for enterprise). All data is sent and received as JSON.
Documentation is pretty comprehensive, check it out. For our task we will need to search repositories, get repository data and list contributors.

We could write all requests by hand, using CURL or file_get_contents(), like in previous blog posts, but today let’s use some library.

I’ve chosen Github-api PHP library. Create new directory and use composer:

require milo/github-api```
1
2
3
4
5
6
7
8
9
10
11
Then to make sure that everything works correctly, create test.php:
``` php
require_once 'vendor/autoload.php';
use Milo\Github;
$api = new Github\Api;
$response = $api->get('/emojis');
$emojis = $api->decode($response);
print_r($emojis);

It should output something like this:
stdClass Object ( [+1] => https://github.global.ssl.fastly.net/images/icons/emoji/+1.png?v5 [-1] => https://github.global.ssl.fastly.net/images/icons/emoji/-1.png?v5 [100] => https://github.global.ssl.fastly.net/images/icons/emoji/100.png?v5 [1234] => https://github.global.ssl.fastly.net/images/icons/emoji/1234.png?v5 [8ball] => https://github.global.ssl.fastly.net/images/icons/emoji/8ball.png?v5 [a] => https://github.global.ssl.fastly.net/images/icons/emoji/a.png?v5 ... )

So basically you do API request and then decode reponse. Ok, now let’s do something useful with it.

Repository script

We need to find repositories by language. Using our previous $api object, it will look like:

1
2
3
4
5
6
7
8
9
$githubData = [
'repository' => [],
'user' => [],
'contributors' => []
];
$repositorySearchResponse= $api->get('/search/repositories', ['q' => 'language:swift', 'per_page' => 5, 'sort' => 'stars', 'order'=>'desc']);
$repositorySearchData= $api->decode($repositorySearchResponse);
print_r($result);

We are searching repositories by language Swift, sorting by number of stars and list 5 items per page. It shows a lot of information, but doesn’t provide number of watchers (check last print_r yourself).

In order to get watchers count we need to get full repository data. We will loop through all repos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
foreach($repositorySearchData->items as $r) {
$fullRepoResponse = $api->get('/repos/:owner/:repo', ['owner' => $r->owner->login, 'repo' => $r->name]);
$fullRepoData = $api->decode($fullRepoResponse);
print_r($fullRepoData);
$repo = [
'id' => $r->id,
'name' => $r->name,
'full_name' => $r->full_name,
'description' => $r->description,
'html_url' => $r->html_url,
'star_count' => $r->stargazers_count,
'fork_count' => $r->forks,
'watchers_count' => $fullRepoData->subscribers_count,
'owner_id' => $r->owner->id
];
$owner = $r->owner;
$user = [
'login' => $owner->login,
'id' => $owner->id,
'avatar_url' => $owner->avatar_url,
'url' => $owner->url,
'html_url' => $owner->html_url,
];
$githubData['repository'][] = $repo;
$githubData['user'][$owner->id] = $user;
}

Couple of things worth noting here. First, Github-api library provides url parameters substitution.

1
$api->get('/repos/:owner/:repo', ['owner' => $r->owner->login, 'repo' => $r->name])

Will make request to /repos/{$r->owner->login}/{$r->name}.

Second, library returns objects and not arrays, so use them accordingly (like $r->owner->login and not like $r[‘owner’][‘login’]).

Now we need to get contributors and that’s it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
foreach($result->items as $r) {
...
$contributorsResponse = $api->get('/repos/:owner/:repo/contributors', ['owner' => $r->owner->login, 'repo' => $r->name]);
$contributorsData = $api->decode($contributorsResponse);
print_r($contributorsData);
foreach($contributorsData as $c) {
$contributor = [
'login' => $c->login,
'id' => $c->id,
'avatar_url' => $c->avatar_url,
'url' => $c->url,
'html_url' => $c->html_url,
];
if(!isset($githubData['user'][$c->id]))$githubData['user'][$c->id] = $contributor;
$githubData['contributors'][] = [
'user_id' => $c->id,
'repo_id' => $r->id,
'contributions' => $c->contributions
];
}
}

To return JSON, we need to set header and encode $githubData.

1
2
3
4
header('Content-Type: application/json');
...
echo json_encode($githubData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

That’s it! But if you try to run script several times, you’ll notice that it will fail because of Github rate limits. Github allows only 60 requests per hour for unauthorized requests.

To overcome this, go to https://github.com/settings/applications, register new application and then generate personal access token. Add this somewhere in the beginning of the script:

1
2
3
$token = new Milo\Github\OAuth\Token('your access token here');
$api->setToken($token);

This will sign every request with this token and raise your rate limits.

Check full script at this Gist: https://gist.github.com/256cats/b8ba88d21031e7e94678