Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ghissue-php

Lightweight PHP library that uses GitHub Issues as a bug tracker for your website. Automatically captures and deduplicates server errors, collects user feedback and feature requests, and displays public issue status — all backed by GitHub's API.

No database required. No external services. Just your website and a GitHub repo.

Features

  • 🐛 Automatic Error Reporting — PHP errors, exceptions, and fatal crashes are automatically filed as GitHub Issues
  • 🔍 Smart Deduplication — Fingerprints errors so the same bug creates one issue with an occurrence counter, not hundreds of duplicates
  • 💬 User Feedback Forms — Drop-in bug report and feature request forms with CSRF protection and spam prevention
  • 📋 Public Issue Board — Display moderated issues on your website (only issues you label as public are shown)
  • 🌐 JavaScript Error Capture — Client-side errors are captured via ghissue.js and reported to the same system
  • 🏢 Multi-Project Support — One GitHub repo can track issues for multiple websites using project labels
  • Rate Limiting — Built-in protection against API flooding during error storms
  • 🔒 Private Traces — Stack traces and server details stay in your (private) GitHub repo, never exposed to end users

Requirements

  • PHP 8.0+
  • curl extension (typically included by default)
  • A GitHub account with a Personal Access Token

Installation

Via Composer (recommended)

composer require kasmok/ghissue-php

Without Composer

Clone or download this repo, then include the single-file autoloader:

require_once '/path/to/ghissue-php/ghissue.php';

That's it — all classes are autoloaded on demand. No build step, no manual requires.

Quick Start

1. Create a GitHub Personal Access Token

Go to GitHub Settings → Tokens and create a token with repo scope (or public_repo for public repos only).

2. Initialize

Option A: Config file (recommended for multi-endpoint sites)

Copy ghissue-config.example.php to your project, fill in your values, then:

use GhIssue\GhIssue;

$tracker = GhIssue::fromConfig(__DIR__ . '/ghissue-config.php');

Option B: Inline

use GhIssue\GhIssue;

$tracker = new GhIssue(
    token:   getenv('GHISSUE_TOKEN'),
    owner:   'your-username',
    repo:    'your-issue-repo',
    project: 'my-website'
);

The storage directory (/tmp/ghissue by default) is created automatically.

3. Set Up Labels (one-time)

Run this once to create the labels ghissue-php uses:

$tracker->setupLabels();

4. Register Error Handler

$tracker->registerErrorHandler([
    'comment_endpoint' => '/ghissue/comment.php',
]);

That's it. Now any unhandled exception automatically creates a GitHub Issue like this:

[my-website] PDOException: Connection refused

Field Value
Class PDOException
Message SQLSTATE[HY000] [2002] Connection refused
File app/Database.php
Line 42

If the same error occurs again, it won't create a duplicate — instead, it adds a comment to the existing issue with a timestamp.

Usage

Automatic Error Reporting

Register the error handler early in your application bootstrap:

$tracker->registerErrorHandler([
    // Show built-in error page to users
    'show_error_page' => true,
    // URL for user comments on the error page
    'comment_endpoint' => '/ghissue/comment.php',
    // Error levels to capture (default: everything except notices)
    'error_levels' => E_ALL & ~E_NOTICE & ~E_DEPRECATED,
    // Include server environment details in report
    'include_environment' => true,
    // Include HTTP request details in report
    'include_request' => true,
]);

Manual Reporting

$tracker->report(
    'Slow database query detected',
    'Query took 12.3s on the /products endpoint',
    'warning'
);

User Feedback Form

Add a feedback form to your website:

$feedback = $tracker->feedback();
$csrfToken = $feedback->generateCsrfToken();
$submitEndpoint = '/feedback';
$project = $tracker->getProject();

include 'vendor/kasmok/ghissue-php/templates/feedback-form.php';

Process submissions:

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $result = $tracker->feedback()->submit($_POST);
    // $result = ['success' => true, 'message' => 'Thank you...']
}

Feedback issues are created with a needs-review label. Add the public label in GitHub to make them visible on the public board.

Public Issue Board

Display approved issues on your website:

$board = $tracker->board();

// Render the built-in template
echo $board->render(
    state: 'open',  // 'open', 'closed', or 'all'
    page: 1,
    type: null       // or 'bug', 'enhancement', etc.
);

// Or fetch raw data for your own template
$data = $board->getIssues('open', 1);
// $data = ['issues' => [...], 'total' => 5, 'page' => 1, 'has_more' => false]

JavaScript Error Capture

Include ghissue.js on your pages:

<script src="/path/to/ghissue.js"></script>
<script>
GhIssue.init({
    endpoint: '/ghissue/client-error.php',
    project: 'my-website',
    maxErrors: 10,       // Max errors per page load
    sampleRate: 1.0,     // Report 100% of errors (0.5 = 50%)
    ignorePatterns: [
        /chrome-extension/,  // Ignore browser extension errors
        /moz-extension/,
    ]
});
</script>

Set up the PHP endpoint (/ghissue/client-error.php):

use GhIssue\ClientErrorHandler;

$handler = new ClientErrorHandler(
    $tracker->github(),
    $tracker->getProject(),
    ['allowed_origins' => ['https://yoursite.com']]
);

header('Content-Type: application/json');
echo json_encode($handler->handle());

Multi-Site Setup

Use one GitHub repo with different project identifiers for each site:

// On site_a.com
$tracker = new GhIssue($token, 'kasmok', 'site-issues', 'site_a');

// On site_b.com
$tracker = new GhIssue($token, 'kasmok', 'site-issues', 'site_b');

Issues are tagged with project:site_a, project:site_b, etc. You can use GitHub's label filters to view issues per site, or see everything at once.

How Deduplication Works

When an error occurs, ghissue-php:

  1. Generates a fingerprint — A hash of the error type, normalized message, file path, and line number
  2. Searches GitHub Issues — Looks for an open issue with a matching fingerprint:abc123def456 label
  3. If found — Adds a "recurring occurrence" comment with a timestamp (no duplicate created)
  4. If not found — Creates a new issue with the fingerprint label

The fingerprint normalizer strips variable data (IDs, timestamps, UUIDs) from error messages so that User 123 not found and User 456 not found produce the same fingerprint.

Moderation Workflow

  1. Automatic errors arrive with the auto-reported label
  2. User feedback arrives with needs-review and user-submitted labels
  3. Review in GitHub — Triage, label, and assign issues as normal
  4. Make public — Add the public label to any issue you want visible on your website's public board
  5. Use Claude Code — With the GitHub MCP server, you can triage issues conversationally

Configuration Reference

GhIssue (main class)

Option Default Description
storage_dir sys_get_temp_dir() . '/ghissue' Directory for rate limiting, cache, and CSRF tokens

ErrorHandler

Option Default Description
rate_limit 30 Max GitHub API calls per hour
error_levels E_ALL & ~E_NOTICE & ~E_DEPRECATED PHP error levels to capture
show_error_page true Show built-in error page to users
error_template Built-in template Path to custom error page template
comment_endpoint null URL for user comment submissions
include_environment true Include server env in issue body
include_request true Include HTTP request in issue body
labels [] Additional labels for all issues
chain_handlers true Call previous error handler after ours

FeedbackHandler

Option Default Description
rate_limit_per_ip 5 Max submissions per hour
csrf_protection true Require CSRF token
csrf_lifetime 3600 Token lifetime in seconds
pending_label needs-review Label for new submissions

PublicBoard

Option Default Description
public_label public Label that marks issues as publicly visible
cache_ttl 300 Cache lifetime in seconds
per_page 20 Issues per page

Security Considerations

  • Never expose your GitHub token to the client side. All API calls happen server-side.
  • Use a dedicated GitHub account (bot account) with limited repo access for the token.
  • The token needs only repo (private repos) or public_repo (public repos) scope.
  • Consider using a private repo for issues so stack traces aren't publicly visible.
  • Set allowed_origins on the client error handler to prevent abuse.
  • The feedback form includes honeypot spam protection and CSRF tokens.

Examples

See the examples/ directory for complete working examples:

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

License

MIT License — see LICENSE for details.

About

Lightweight PHP library that uses GitHub Issues as a bug tracker for your website. Automatically captures and deduplicates server errors, collects user feedback and feature requests, and displays public issue status — all backed by GitHub's API.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages