Thank you for your interest in contributing to the CryptNote PHP Library! This guide will help you get started.
- Code of Conduct
- Getting Started
- Development Setup
- Running Tests
- Code Style Guidelines
- Pull Request Process
- Reporting Issues
- Security Vulnerabilities
By participating in this project, you agree to maintain a respectful and inclusive environment. We expect all contributors to:
- Be respectful and considerate
- Welcome newcomers and help them learn
- Focus on constructive feedback
- Accept responsibility for mistakes and learn from them
- PHP 8.0 or higher
- Composer
- Git
- OpenSSL extension
- PDO extension with SQLite driver
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/cryptnote-php.git
cd cryptnote-php- Add the upstream remote:
git remote add upstream https://github.com/dolutech/cryptnote-php.gitcomposer installcryptnote-php/
├── src/
│ ├── CryptNote.php # Main class with database storage
│ └── CryptNoteStandalone.php # Standalone encryption utilities
├── tests/
│ └── CryptNoteTest.php # PHPUnit tests
├── examples/
│ ├── basic-usage.php # Basic usage examples
│ ├── standalone-encryption.php
│ └── web-interface/ # Web interface example
├── docs/ # Documentation
├── composer.json
├── phpunit.xml
└── README.md
git checkout -b feature/your-feature-name./vendor/bin/phpunit./vendor/bin/phpunit tests/CryptNoteTest.php./vendor/bin/phpunit --filter testCreateSimpleNote./vendor/bin/phpunit --coverage-html coverage/Then open coverage/index.html in your browser.
Tests use a temporary SQLite database that is automatically cleaned up. The test configuration is in phpunit.xml:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
colors="true"
verbose="true">
<testsuites>
<testsuite name="CryptNote Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>When adding new features, include tests:
<?php
namespace CryptNote\Tests;
use PHPUnit\Framework\TestCase;
use CryptNote\CryptNote;
class YourFeatureTest extends TestCase
{
private CryptNote $cryptnote;
private string $testDbPath;
protected function setUp(): void
{
$this->testDbPath = sys_get_temp_dir() . '/cryptnote_test_' . uniqid() . '.db';
$this->cryptnote = new CryptNote([
'db_path' => $this->testDbPath,
'auto_cleanup' => false,
]);
}
protected function tearDown(): void
{
// Clean up test database
@unlink($this->testDbPath);
@unlink($this->testDbPath . '-wal');
@unlink($this->testDbPath . '-shm');
}
public function testYourFeature(): void
{
// Arrange
$content = 'Test content';
// Act
$result = $this->cryptnote->create($content);
// Assert
$this->assertTrue($result['success']);
$this->assertNotEmpty($result['token']);
}
}We follow PSR-12 coding standards with some additions:
// Classes: PascalCase
class CryptNote { }
class CryptNoteStandalone { }
// Methods: camelCase
public function createNote() { }
private function validateToken() { }
// Variables: camelCase
$encryptedData = '';
$maxViews = 1;
// Constants: UPPER_SNAKE_CASE
const MAX_TOKEN_LENGTH = 64;Always use type declarations:
// ✅ Good
public function create(string $content, array $options = []): array
{
// ...
}
// ❌ Bad
public function create($content, $options = [])
{
// ...
}Use PHPDoc for all public methods:
/**
* Create an encrypted note.
*
* @param string $content The content to encrypt
* @param array $options Creation options:
* - password: Optional password for protection
* - max_views: Maximum views (1-100)
* - expire_minutes: Minutes until expiration
* @return array Contains 'token', 'has_password', etc.
* @throws Exception If content is empty or exceeds max length
*/
public function create(string $content, array $options = []): array
{
// ...
}Use exceptions for error conditions:
// ✅ Good
if (empty($content)) {
throw new Exception('Content cannot be empty');
}
// ❌ Bad
if (empty($content)) {
return ['error' => 'Content cannot be empty'];
}Use 4 spaces for indentation (no tabs).
Keep lines under 120 characters when possible.
Use Allman style for classes, K&R for methods:
class CryptNote
{
public function create(string $content): array
{
if ($condition) {
// ...
}
}
}Use short array syntax:
// ✅ Good
$options = [
'password' => null,
'max_views' => 1,
];
// ❌ Bad
$options = array(
'password' => null,
'max_views' => 1,
);Run static analysis before submitting:
# If PHPStan is installed
./vendor/bin/phpstan analyse src tests
# If Psalm is installed
./vendor/bin/psalm-
Update your fork:
git fetch upstream git rebase upstream/main
-
Run tests:
./vendor/bin/phpunit
-
Check code style:
# Manual review or use PHP_CodeSniffer ./vendor/bin/phpcs --standard=PSR12 src/ -
Update documentation if needed
-
Push your branch:
git push origin feature/your-feature-name
-
Open a Pull Request on GitHub
-
Fill out the PR template:
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Tests pass locally
- [ ] New tests added for new features
- [ ] Documentation updated
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-reviewed code
- [ ] Commented complex code
- [ ] No new warnings- Maintainers will review your PR
- Address any feedback
- Once approved, your PR will be merged
# Update your local main
git checkout main
git pull upstream main
# Delete your feature branch
git branch -d feature/your-feature-name
git push origin --delete feature/your-feature-nameWhen reporting bugs, include:
- PHP version:
php -v - Library version: Check
composer.json - Operating system
- Steps to reproduce
- Expected behavior
- Actual behavior
- Error messages (if any)
Use this template:
## Bug Description
Clear description of the bug
## Environment
- PHP Version: 8.2.0
- Library Version: 1.0.0
- OS: Ubuntu 22.04
## Steps to Reproduce
1. Initialize CryptNote with...
2. Call create() with...
3. See error
## Expected Behavior
What should happen
## Actual Behavior
What actually happens
## Error MessagesPaste any error messages here
## Additional Context
Any other relevant information
For feature requests, include:
- Use case: Why is this feature needed?
- Proposed solution: How should it work?
- Alternatives considered: Other approaches you've thought of
- Additional context: Examples, mockups, etc.
Do not report security vulnerabilities through public issues.
Instead:
- Email: [email protected]
- Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We will respond within 48 hours and work with you to address the issue.
// Enable error reporting during development
error_reporting(E_ALL);
ini_set('display_errors', '1');
// Use var_dump for quick debugging
var_dump($result);
// Or use a debugger like Xdebug// Test encryption/decryption manually
$crypto = new CryptNoteStandalone();
$key = $crypto->generateKey();
$original = "Test message";
$encrypted = $crypto->encrypt($original, $key);
$decrypted = $crypto->decrypt($encrypted, $key);
assert($original === $decrypted, "Encryption/decryption failed");# View database contents (for debugging)
sqlite3 /path/to/cryptnote.db
sqlite> .tables
sqlite> .schema encrypted_content
sqlite> SELECT token, has_password, remaining_views FROM encrypted_content;Contributors will be recognized in:
- The project README
- Release notes
- The contributors page on GitHub
Thank you for contributing to CryptNote! 🔐