Our AI detection models just got upgraded. They now catch ChatGPT and Claude in student code more accurately than ever. See what's new
Developer API

Code Plagiarism
Detection API

Build plagiarism detection into your apps. Check code against 20+ billion sources.

const response = await fetch('https://codequiry.com/api/v1/check', { method: 'POST', headers: { 'apikey': 'YOUR_API_KEY' }, body: formData }); // Check created!
PHP SDK

Codequiry SDK for PHP

The official PHP SDK for Codequiry provides a clean, object-oriented interface for integrating plagiarism detection into your PHP applications. Compatible with modern PHP frameworks including Laravel, Symfony, and CodeIgniter.

Open Source: View the complete source code and contribute at github.com/cqchecker/codequiry-php

Installation

Composer (Recommended)
        composer require codequiry/codequiry-php
        
Composer
Manual Installation
        git clone https://github.com/cqchecker/codequiry-php.git
cd codequiry-php
composer install
        
Manual
Requirements: PHP 7.4 or higher, cURL extension, JSON extension

Quick Start

1. Basic Setup
        @php

require_once 'vendor/autoload.php';

use Codequiry\Client;
use Codequiry\Exceptions\CodequiryException;

// Initialize the client
$client = new Client([
    'api_key' => 'your-api-key-here',
    'base_url' => 'https://codequiry.com/api/v1', // Optional
    'timeout' => 30, // Request timeout in seconds
]);

// Test connection
try {
    $account = $client->getAccountInfo();
    echo "Connected as: " . $account['name'] . PHP_EOL;
    echo "Checks remaining: " . $account['checks_remaining'] . PHP_EOL;
} catch (CodequiryException $e) {
    echo "Connection failed: " . $e->getMessage() . PHP_EOL;
}
        
Basic Setup
2. Complete Workflow Example
        @php

class PlagiarismChecker
{
    private $client;

    public function __construct($apiKey)
    {
        $this->client = new Client(['api_key' => $apiKey]);
    }

    public function runCompleteCheck($assignmentName, $language, array $filePaths)
    {
        try {
            // 1. Create a new check
            $check = $this->client->createCheck([
                'name' => $assignmentName,
                'language' => $language
            ]);

            echo "Created check: {$check['id']}" . PHP_EOL;

            // 2. Upload files
            $uploadedFiles = [];
            foreach ($filePaths as $filePath) {
                if (!file_exists($filePath)) {
                    throw new Exception("File not found: {$filePath}");
                }

                $result = $this->client->uploadFile($check['id'], $filePath);
                $uploadedFiles[] = $result;
                echo "Uploaded: {$result['filename']}" . PHP_EOL;
            }

            // 3. Start the analysis
            $analysis = $this->client->startCheck($check['id'], [
                'webcheck' => true,  // Check against web sources
                'dbcheck' => true    // Check against database
            ]);

            echo "Analysis started..." . PHP_EOL;

            // 4. Wait for completion
            $results = $this->waitForCompletion($check['id']);

            // 5. Get overview results
            $overview = $this->client->getOverview($check['id']);

            echo "Analysis complete!" . PHP_EOL;
            echo "Found {$overview['submissions_count']} submissions" . PHP_EOL;

            // 6. Process results
            $suspiciousSubmissions = array_filter(
                $overview['submissions'],
                function($sub) {
                    return floatval($sub['total_result']) > 50;
                }
            );

            foreach ($suspiciousSubmissions as $submission) {
                echo "⚠️  {$submission['filename']}: {$submission['total_result']}% similarity" . PHP_EOL;

                // Get detailed results
                $details = $this->client->getDetailedResults($check['id'], $submission['id']);

                // Process other matches
                foreach ($details['other_matches'] as $match) {
                    echo "  → Match with {$match['file_matched']}: {$match['similarity']}%" . PHP_EOL;
                }
            }

            return $overview;

        } catch (Exception $e) {
            echo "Error: " . $e->getMessage() . PHP_EOL;
            throw $e;
        }
    }

    private function waitForCompletion($checkId, $maxWaitTime = 600)
    {
        $startTime = time();

        while (time() - $startTime < $maxWaitTime) {
            $status = $this->client->getCheckStatus($checkId);

            if ($status['status_id'] == 4) { // Completed
                return $status;
            }

            echo "Status: " . ($status['message'] ?? 'Processing...') . PHP_EOL;
            sleep(30); // Wait 30 seconds before checking again
        }

        throw new Exception("Check did not complete within {$maxWaitTime} seconds");
    }
}

// Usage
$checker = new PlagiarismChecker('your-api-key-here');

$results = $checker->runCompleteCheck(
    'Assignment 1 - PHP Basics',
    3, // PHP language ID
    [
        'student1_submission.php',
        'student2_submission.php',
        'student3_submission.php'
    ]
);

echo "Check completed successfully!" . PHP_EOL;
        
Complete Workflow

Laravel Integration

Seamlessly integrate Codequiry into your Laravel applications:

1. Environment Configuration
        # .env
CODEQUIRY_API_KEY=your-api-key-here
CODEQUIRY_BASE_URL=https://codequiry.com/api/v1
        
.env Configuration
2. Service Provider
        @php

// app/Providers/CodequiryServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Codequiry\Client;

class CodequiryServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(Client::class, function ($app) {
            return new Client([
                'api_key' => config('services.codequiry.api_key'),
                'base_url' => config('services.codequiry.base_url'),
                'timeout' => config('services.codequiry.timeout', 30),
            ]);
        });
    }

    public function boot()
    {
        //
    }
}
        
Service Provider
3. Controller Example
        @php

// app/Http/Controllers/PlagiarismController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Codequiry\Client;
use App\Assignment;
use App\Jobs\ProcessPlagiarismCheck;

class PlagiarismController extends Controller
{
    private $codequiry;

    public function __construct(Client $codequiry)
    {
        $this->codequiry = $codequiry;
    }

    public function upload(Request $request)
    {
        $request->validate([
            'assignment_id' => 'required|exists:assignments,id',
            'files.*' => 'required|file|max:10000', // 10MB max
        ]);

        $assignment = Assignment::findOrFail($request->assignment_id);

        try {
            // Create check
            $check = $this->codequiry->createCheck([
                'name' => $assignment->title,
                'language' => $assignment->language_id
            ]);

            // Store check ID
            $assignment->update(['codequiry_check_id' => $check['id']]);

            // Upload files
            $uploadedFiles = [];
            foreach ($request->file('files') as $file) {
                $tempPath = $file->store('temp');
                $fullPath = storage_path('app/' . $tempPath);

                $result = $this->codequiry->uploadFile($check['id'], $fullPath, $file->getClientOriginalName());
                $uploadedFiles[] = $result;

                // Clean up temp file
                unlink($fullPath);
            }

            // Start analysis in background
            ProcessPlagiarismCheck::dispatch($assignment);

            return response()->json([
                'success' => true,
                'check_id' => $check['id'],
                'uploaded_files' => count($uploadedFiles),
                'message' => 'Files uploaded successfully. Analysis started.'
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage()
            ], 500);
        }
    }

    public function status(Assignment $assignment)
    {
        if (!$assignment->codequiry_check_id) {
            return response()->json(['error' => 'No check ID found'], 404);
        }

        try {
            $status = $this->codequiry->getCheckStatus($assignment->codequiry_check_id);

            if ($status['status_id'] == 4) { // Completed
                $overview = $this->codequiry->getOverview($assignment->codequiry_check_id);

                return response()->json([
                    'status' => 'completed',
                    'results' => $overview
                ]);
            }

            return response()->json([
                'status' => 'processing',
                'message' => $status['message'] ?? 'Analysis in progress...'
            ]);

        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }
}
        
Laravel Controller
4. Background Job
        @php

// app/Jobs/ProcessPlagiarismCheck.php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Assignment;
use Codequiry\Client;

class ProcessPlagiarismCheck implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $assignment;

    public function __construct(Assignment $assignment)
    {
        $this->assignment = $assignment;
    }

    public function handle(Client $codequiry)
    {
        try {
            // Start the check
            $codequiry->startCheck($this->assignment->codequiry_check_id, [
                'webcheck' => true,
                'dbcheck' => true
            ]);

            // Wait for completion (with timeout)
            $maxWaitTime = 600; // 10 minutes
            $startTime = time();

            while (time() - $startTime < $maxWaitTime) {
                $status = $codequiry->getCheckStatus($this->assignment->codequiry_check_id);

                if ($status['status_id'] == 4) { // Completed
                    // Get results and store in database
                    $overview = $codequiry->getOverview($this->assignment->codequiry_check_id);

                    $this->assignment->update([
                        'plagiarism_results' => json_encode($overview),
                        'plagiarism_status' => 'completed',
                        'processed_at' => now()
                    ]);

                    // Send notification to instructor
                    $this->assignment->instructor->notify(
                        new PlagiarismCheckCompleted($this->assignment)
                    );

                    return;
                }

                sleep(30); // Wait 30 seconds before checking again
            }

            // Timeout occurred
            $this->assignment->update(['plagiarism_status' => 'timeout']);

        } catch (\Exception $e) {
            $this->assignment->update([
                'plagiarism_status' => 'failed',
                'plagiarism_error' => $e->getMessage()
            ]);

            throw $e; // Re-throw to mark job as failed
        }
    }
}
        
Background Job

Advanced Features

File Upload Methods
        @php

// Upload from file path
$result = $client->uploadFile($checkId, './code.php');

// Upload from string content
$code = 'Hello World';
$result = $client->uploadString($checkId, $code, 'hello.php');

// Upload with custom filename
$result = $client->uploadFile($checkId, './temp.php', 'student1.php');

// Bulk upload
$files = ['file1.php', 'file2.php', 'file3.php'];
$results = $client->uploadMultiple($checkId, $files);

// Upload with progress callback
$result = $client->uploadFile($checkId, './large-file.php', null, function($uploaded, $total) {
    $percent = round(($uploaded / $total) * 100);
    echo "Upload progress: {$percent}%" . PHP_EOL;
});
        
Upload Methods
Configuration & Options
        @php

// Client configuration
$client = new Client([
    'api_key' => 'your-api-key',
    'base_url' => 'https://codequiry.com/api/v1',
    'timeout' => 30,
    'retries' => 3,
    'debug' => false,
    'user_agent' => 'MyApp/1.0'
]);

// Analysis options
$client->startCheck($checkId, [
    'webcheck' => true,     // Check web sources
    'dbcheck' => false,     // Skip database check
    'test_type' => 1,       // Analysis engine type
    'sensitivity' => 'high' // Detection sensitivity
]);

// Custom headers
$client->setHeaders([
    'X-Custom-Header' => 'value',
    'X-Client-Version' => '1.0'
]);
        
Configuration

Error Handling & Best Practices

        @php

use Codequiry\Exceptions\CodequiryException;
use Codequiry\Exceptions\RateLimitException;
use Codequiry\Exceptions\UnauthorizedException;

class RobustPlagiarismChecker
{
    private $client;
    private $maxRetries;

    public function __construct($apiKey, $maxRetries = 3)
    {
        $this->client = new Client(['api_key' => $apiKey]);
        $this->maxRetries = $maxRetries;
    }

    public function checkWithRetry($assignment, $retryCount = 0)
    {
        try {
            return $this->performCheck($assignment);

        } catch (RateLimitException $e) {
            if ($retryCount < $this->maxRetries) {
                // Wait with exponential backoff
                $waitTime = pow(2, $retryCount) * 1000000; // microseconds
                usleep($waitTime);

                return $this->checkWithRetry($assignment, $retryCount + 1);
            }
            throw new Exception("Rate limit exceeded after {$this->maxRetries} retries");

        } catch (UnauthorizedException $e) {
            throw new Exception("Invalid API key or access denied");

        } catch (CodequiryException $e) {
            if ($e->getCode() === 422) {
                throw new Exception("Invalid request: " . $e->getMessage());
            }

            if ($retryCount < $this->maxRetries) {
                sleep(2 * ($retryCount + 1)); // Linear backoff for other errors
                return $this->checkWithRetry($assignment, $retryCount + 1);
            }

            throw new Exception("Check failed after {$this->maxRetries} attempts: " . $e->getMessage());
        }
    }

    private function performCheck($assignment)
    {
        // Validate input
        if (empty($assignment['files'])) {
            throw new InvalidArgumentException('No files provided for analysis');
        }

        foreach ($assignment['files'] as $file) {
            if (!file_exists($file)) {
                throw new InvalidArgumentException("File not found: {$file}");
            }

            $fileSize = filesize($file);
            if ($fileSize > 10 * 1024 * 1024) { // 10MB limit
                throw new InvalidArgumentException("File too large: {$file} ({$fileSize} bytes)");
            }
        }

        // Create check
        $check = $this->client->createCheck([
            'name' => $assignment['name'] ?? 'Untitled Check',
            'language' => $assignment['language'] ?? 1
        ]);

        echo "Created check: {$check['id']}" . PHP_EOL;

        // Upload files with progress
        $totalFiles = count($assignment['files']);
        $uploaded = 0;

        foreach ($assignment['files'] as $file) {
            try {
                $result = $this->client->uploadFile($check['id'], $file);
                $uploaded++;
                echo "Progress: {$uploaded}/{$totalFiles} files uploaded" . PHP_EOL;

            } catch (Exception $e) {
                echo "Failed to upload {$file}: " . $e->getMessage() . PHP_EOL;
                // Continue with other files
            }
        }

        if ($uploaded === 0) {
            throw new Exception('No files were successfully uploaded');
        }

        // Start analysis
        $this->client->startCheck($check['id'], [
            'webcheck' => $assignment['check_web'] ?? true,
            'dbcheck' => $assignment['check_database'] ?? true
        ]);

        echo "Analysis started for {$uploaded} files..." . PHP_EOL;

        // Monitor progress
        return $this->waitForCompletion($check['id']);
    }

    private function waitForCompletion($checkId, $timeout = 600)
    {
        $startTime = time();
        $lastStatus = '';

        while (time() - $startTime < $timeout) {
            $status = $this->client->getCheckStatus($checkId);

            if ($status['status_id'] == 4) { // Completed
                echo "Analysis completed!" . PHP_EOL;
                return $this->client->getOverview($checkId);
            }

            $currentStatus = $status['message'] ?? 'Processing...';
            if ($currentStatus !== $lastStatus) {
                echo "Status: {$currentStatus}" . PHP_EOL;
                $lastStatus = $currentStatus;
            }

            sleep(30);
        }

        throw new Exception("Analysis did not complete within {$timeout} seconds");
    }

    public function generateReport($checkId, $format = 'json')
    {
        $overview = $this->client->getOverview($checkId);

        switch ($format) {
            case 'csv':
                return $this->generateCsvReport($overview);
            case 'html':
                return $this->generateHtmlReport($overview);
            default:
                return $overview;
        }
    }

    private function generateCsvReport($overview)
    {
        $csv = "Filename,Total Similarity,Web Matches,Peer Matches\n";

        foreach ($overview['submissions'] as $submission) {
            $csv .= sprintf(
                "%s,%.2f%%,%d,%d\n",
                $submission['filename'],
                $submission['total_result'],
                $submission['web_matches'] ?? 0,
                $submission['other_matches'] ?? 0
            );
        }

        return $csv;
    }
}

// Usage
try {
    $checker = new RobustPlagiarismChecker(getenv('CODEQUIRY_API_KEY'));

    $results = $checker->checkWithRetry([
        'name' => 'Final Project - E-commerce Site',
        'language' => 3, // PHP
        'files' => [
            'student1/index.php',
            'student2/index.php',
            'student3/index.php'
        ],
        'check_web' => true,
        'check_database' => true
    ]);

    // Generate CSV report
    $csvReport = $checker->generateReport($results['check_id'], 'csv');
    file_put_contents('plagiarism_report.csv', $csvReport);

    echo "Check completed and report saved!" . PHP_EOL;

} catch (Exception $e) {
    error_log("Plagiarism check failed: " . $e->getMessage());
    echo "Error: " . $e->getMessage() . PHP_EOL;
}
        
Error Handling