username = $usr_name; } public function authenticate($auth_key, $client_id, $client_secret) { $url = sprintf(self::API_TOKEN, $client_id, $client_secret, $auth_key); $result = file_get_contents($url); $result = str_replace('access_token=', '', $result); $result = str_replace('&scope=&token_type=bearer', '', $result); setToken($result); } public function setSessionOutput($sout) { $this->sessionOutput = $sout; } public function setRawDataPath($rdp) { $this->FILE_RAW_DATA = $rdp; } public function setFinDataPath($fdp) { $this->FILE_FINISHED_DATA = $fdp; } public function setBasicAuthentication($usr, $passw) { $this->basicAuth = "Authorization: Basic " . base64_encode($usr . ":" . $passw); } public function setToken($token) { $this->token = $token; $this->tokenHeader = 'access_token=' . $token . '&token_type=bearer'; } public function collect() { set_time_limit(300); // 5min $this->output_flushed_clear(); $this->output_flushed("Start progress"); $this->listRepositories(); $this->listAllCommits(); $this->save(); $this->output_flushed("Remaining Requests: " . $this->getRemainingRequests()); $this->output_flushed("Finished progress"); } private function listRepositories() { $this->repositories = array(); $this->listRepositoriesForUser($this->username); foreach ($this->sec_username as $un) { $this->listRepositoriesForUser($un); } foreach($this->sec_repo as $srep) { $this->listSingleRepo($srep); } } private function listRepositoriesForUser($usr) { $page = 1; $url = sprintf(self::API_REPOSITORIESLIST . '&' . $this->tokenHeader, $usr, $page); $result = $this->getJSON($url); while (! empty($result)) { foreach ($result as $result_repo) { $this->repositories[] = $this->parseRepoJSON($result_repo); $this->output_flushed("Found Repo: " . $result_repo->{'full_name'}); } //########## $url = sprintf(self::API_REPOSITORIESLIST . '&' . $this->tokenHeader, $usr, ++$page); $result = $this->getJSON($url); } } private function listSingleRepo($repo) { $url = sprintf(self::API_SINGLEREPOSITORY . '?' . $this->tokenHeader, $repo); $result_repo = $this->getJSON($url); if (! empty($result_repo)) { $this->repositories[] = $this->parseRepoJSON($result_repo); $this->output_flushed("Found Repo: " . $result_repo->{'full_name'}); } } private function getJSON($url) { if (array_key_exists('HTTP_USER_AGENT', $_SERVER)) { $options = ['http' => ['user_agent'=> $_SERVER['HTTP_USER_AGENT']]]; } else { $options = ['http' => ['user_agent'=> 'ExtendedGitGraph_for_mikescher.com']]; } if ($this->basicAuth != null) { $options = [ 'http' => [ 'user_agent' => $options['http']['user_agent'], 'header' => $this->basicAuth, ] ]; } $context = stream_context_create($options); $response = @file_get_contents($url, false, $context); if ($response === false) { $this->output_flushed("Error recieving json: '" . $url . "'"); return array(); } return json_decode($response); } private function getRemainingRequests() { $json = $this->getJSON(self::API_RATELIMIT . '?' . $this->tokenHeader); return $json->{'resources'}->{'core'}->{'remaining'}; } private function listAllCommits() { $this->commits = array(); foreach($this->repositories as $repo) { $this->listCommits($repo); } } private function listCommits($repo) { $page = 1; $url = $repo['commits_url'] . '?per_page=100&page=' . $page . '&author=' .$this->username . '&' .$this->tokenHeader; $result = $this->getJSON($url); $commit_list = array(); while (! empty($result)) { foreach ($result as $result_commit) { $commit_list[] = $this->parseCommitJSON($repo, $result_commit); } $this->output_flushed("Found " . count($result) . " Commits from " . $repo['full_name']); //########## $url = $repo['commits_url'] . '?per_page=100&page=' . ++$page . '&author=' .$this->username . '&' .$this->tokenHeader; $result = $this->getJSON($url); } $this->commits = array_merge($this->commits, $commit_list); } private function parseRepoJSON($json) { return [ 'id' => $json->{'id'}, 'name' => $json->{'name'}, 'full_name' => $json->{'full_name'}, 'owner' => $json->{'owner'}->{'login'}, 'owner_id' => $json->{'owner'}->{'id'}, 'owner_avatar-url' => $json->{'owner'}->{'avatar_url'}, 'owner_gravatar-id' => $json->{'owner'}->{'gravatar_id'}, 'url' => $json->{'html_url'}, 'language' => $json->{'language'}, 'url' => $json->{'html_url'}, 'creation' => DateTime::createFromFormat(DateTime::ISO8601, $json->{'created_at'}), 'size' => $json->{'size'}, 'default_branch' => $json->{'default_branch'}, 'commits_url' => str_replace('{/sha}', '', $json->{'commits_url'}), ]; } private function parseCommitJSON($repo, $json) { return [ 'sha' => $json->{'sha'}, 'author_name' => $json->{'commit'}->{'author'}->{'name'}, 'author_mail' => $json->{'commit'}->{'author'}->{'email'}, 'author_login' => $json->{'author'}->{'login'}, 'author_id' => $json->{'author'}->{'id'}, 'sha' => $json->{'sha'}, 'message' => $json->{'commit'}->{'message'}, 'repository' => $repo, 'date' => DateTime::createFromFormat(DateTime::ISO8601, $json->{'commit'}->{'author'}->{'date'}), ]; } private function save() { $this->output_flushed("Start saving data"); $save = serialize( [ 'repositories' => $this->repositories, 'commits' => $this->commits, ]); file_put_contents($this->FILE_RAW_DATA, $save); $this->output_flushed('Finished saving data'); } public function output_flushed_clear() { if ($this->sessionOutput) { if (session_status() !== PHP_SESSION_ACTIVE) session_start(); $_SESSION[self::PROGRESS_SESSION_COOKIE] = ''; session_commit(); } } public function output_flushed($txt) { if ($this->sessionOutput) { if (session_status() !== PHP_SESSION_ACTIVE) session_start(); $_SESSION[self::PROGRESS_SESSION_COOKIE] .= '[' . date('H:i.s') . '] ' . $txt . "\r\n"; session_commit(); } else { print $txt; print "\n"; } } public function loadData() { $data = unserialize(file_get_contents($this->FILE_RAW_DATA)); $this->repositories = $data['repositories']; $this->commits = $data['commits']; } public function generate($year) { $ymap = $this->generateYearMap($year); // unused on purpose (template.php needs it) $ymapmax = min($this->getMaxCommitCount(), self::COMMITCOUNT_COLOR_UPPERLIMIT); // unused on purpose (template.php needs it) ob_start(); include('template.php'); $returned = ob_get_contents(); ob_end_clean(); return $returned; } public function generateAndSave() { $result = ''; foreach($this->getYears() as $year) { $result.= $this->generate($year); $result.= '
'; } $this->generateCommitMap(); file_put_contents($this->FILE_FINISHED_DATA, serialize( [ 'creation' => new DateTime(), 'total' => count($this->commits), 'repos' => count($this->repositories), 'streak' => $this->getLongestStreak(), 'streak_start' => $this->getLongestStreakStart(), 'streak_end' => $this->getLongestStreakEnd(), 'max_commits' => $this->getMaxCommits(), 'max_commits_date' => $this->getMaxCommitsDate(), 'avg_commits' => $this->getAvgCommits(), 'start' => $this->startdate, 'end' => $this->enddate, 'content' => $result, ])); return $result; } private function generateCommitMap() { $this->commitmap = array(); $this->startdate = $this->getStartDate(); $this->enddate = $this->getEndDate(); $date = clone $this->startdate; while($date < $this->enddate) { $this->commitmap[$date->format('Y-m-d')] = 0; $date = $date->modify("+1 day"); } foreach ($this->commits as $commit) { if(array_key_exists($commit['date']->format('Y-m-d'), $this->commitmap)) $this->commitmap[$commit['date']->format('Y-m-d')]++; } } private function getStartDate() { $date = $this->commits[0]['date']; foreach($this->commits as $commit) { if ($commit['date'] < $date) { $date = clone $commit['date']; } } return new DateTime($date->format('Y-m-d')); } private function getEndDate() { $date = $this->commits[0]['date']; foreach($this->commits as $commit) { if ($commit['date'] > $date) { $date = clone $commit['date']; } } return new DateTime($date->format('Y-m-d')); } private function getCommitsForDate($d) { $v = $d->format('Y-m-d'); if (array_key_exists($v, $this->commitmap)) return $this->commitmap[$d->format('Y-m-d')]; else return 0; } private function getLongestStreak() { /* @var $curr DateTime */ /* @var $end DateTime */ $curr = clone $this->startdate; $end = clone $this->enddate; $streak_curr = 0; $streak_max = 0; while ($curr <= $end) { if ($this->getCommitsForDate($curr) > 0) { $streak_curr++; } else { $streak_max = max($streak_max, $streak_curr); $streak_curr = 0; } $curr = $curr->modify('+1 day'); } $streak_max = max($streak_max, $streak_curr); return $streak_max; } private function getLongestStreakStart() { /* @var $curr DateTime */ /* @var $end DateTime */ $curr = clone $this->startdate; $end = clone $this->enddate; $streak_curr_start = clone $curr; $streak_max_start = null; $streak_curr = 0; $streak_max = 0; while ($curr <= $end) { if ($this->getCommitsForDate($curr) > 0) { $streak_curr++; } else { if ($streak_curr > $streak_max) { $streak_max = $streak_curr; $streak_max_start = clone $streak_curr_start; } $streak_curr = 0; $streak_curr_start = clone $curr; } $curr = $curr->modify('+1 day'); } if ($streak_curr > $streak_max) { $streak_max_start = clone $streak_curr_start; } return $streak_max_start; } private function getLongestStreakEnd() { /* @var $curr DateTime */ /* @var $end DateTime */ $curr = clone $this->startdate; $end = clone $this->enddate; $streak_max_end = null; $streak_curr = 0; $streak_max = 0; while ($curr <= $end) { if ($this->getCommitsForDate($curr) > 0) { $streak_curr++; } else { if ($streak_curr > $streak_max) { $streak_max = $streak_curr; $streak_max_end = clone $curr; } $streak_curr = 0; } $curr = $curr->modify('+1 day'); } if ($streak_curr > $streak_max) { $streak_max_end = clone $curr; } return $streak_max_end; } private function getMaxCommits() { /* @var $curr DateTime */ /* @var $end DateTime */ $curr = clone $this->startdate; $end = clone $this->enddate; $max = 0; while ($curr <= $end) { $max = max($max, $this->getCommitsForDate($curr)); $curr = $curr->modify('+1 day'); } return $max; } private function getMaxCommitsDate() { /* @var $curr DateTime */ /* @var $end DateTime */ $curr = clone $this->startdate; $end = clone $this->enddate; $max = 0; $max_date = null; while ($curr <= $end) { $c = $this->getCommitsForDate($curr); if ($c >= $max) { $max = $c; $max_date = clone $curr; } $max = max($max, $this->getCommitsForDate($curr)); $curr = $curr->modify('+1 day'); } return $max_date; } private function getAvgCommits() { /* @var $curr DateTime */ /* @var $end DateTime */ $curr = clone $this->startdate; $end = clone $this->enddate; $max = array(); while ($curr <= $end) { $max[] = $this->getCommitsForDate($curr); $curr = $curr->modify('+1 day'); } $sum = array_sum($max); $count = count($max); return $sum / $count; } public function loadFinishedContent() { $data = unserialize(file_get_contents($this->FILE_FINISHED_DATA)); return $data['content']; } public function loadFinishedData() { $data = unserialize(file_get_contents($this->FILE_FINISHED_DATA)); return $data; } private function getMaxCommitCount() { $max = 0; foreach($this->getYears() as $year) { $max = max($max, max($this->generateYearMap($year))); } return $max; } private function generateYearMap($year) { $ymap = array(); $date = new DateTime($year . '-01-01'); while($date->format('Y') == $year) { $ymap[$date->format('Y-m-d')] = 0; $date = $date->modify("+1 day"); } foreach ($this->commits as $commit) { if(array_key_exists($commit['date']->format('Y-m-d'), $ymap)) $ymap[$commit['date']->format('Y-m-d')]++; } return $ymap; } public function getYears() { $years = array(); foreach ($this->commits as $commit) { if(! in_array($commit['date']->format('Y'), $years)) $years[] = $commit['date']->format('Y'); } asort($years); return $years; } public function addSecondaryUsername($sun) { $this->sec_username[] = $sun; } public function addSecondaryRepository($sre) { $this->sec_repo[] = $sre; } }