Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on:
push:
branches:
- main
- master
pull_request:

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-version: ['8.1', '8.2', '8.3', '8.4']

steps:
- name: Check out repository
uses: actions/checkout@v7.0.1

- name: Set up PHP
uses: shivammathur/setup-php@2.37.2
with:
php-version: ${{ matrix.php-version }}
coverage: none

- name: Validate composer configuration
run: composer validate --strict

- name: Install dependencies
run: composer install --no-interaction --prefer-dist

- name: Run test suite
run: composer test
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
vendor
vendor/
composer.phar
composer.lock
.DS_Store
build
build/
.phpunit.cache/
.phpunit.result.cache
19 changes: 0 additions & 19 deletions .travis.yml

This file was deleted.

101 changes: 56 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
[![Build Status](https://travis-ci.org/zackkitzmiller/tiny-php.png?branch=master)](https://travis-ci.org/zackkitzmiller/tiny-php)
[![Coverage Status](https://coveralls.io/repos/zackkitzmiller/tiny-php/badge.png?branch=master)](https://coveralls.io/r/zackkitzmiller/tiny-php?branch=master)
[![CI](https://github.com/zackkitzmiller/tiny-php/actions/workflows/ci.yml/badge.svg)](https://github.com/zackkitzmiller/tiny-php/actions/workflows/ci.yml)

# Tiny

A reversible base62 ID obfuscater
Tiny is a small reversible ID obfuscator for PHP. It encodes integers into a custom alphabet and decodes them back again.

## Authors
## What's modernized

Originally by Jacob DeHart, with Ruby and Python ports by Kyle Bragger

Now maintained by [Zack Kitzmiller](https://github.com/zackkitzmiller).
- PHP 8.1+ baseline
- PSR-4 autoloading
- PHPUnit 10/11 test suite
- GitHub Actions CI
- Safer alphabet validation and decoding errors

## Installation

Install via Composer

```json
{
"require": {
"zackkitzmiller/tiny": "1.2.0"
},
}
```bash
composer require zackkitzmiller/tiny
```

## Usage

```php
$tiny = new \ZackKitzmiller\Tiny('5SX0TEjkR1mLOw8Gvq2VyJxIFhgCAYidrclDWaM3so9bfzZpuUenKtP74QNH6B');
<?php

use ZackKitzmiller\Tiny;

$tiny = new Tiny('5SX0TEjkR1mLOw8Gvq2VyJxIFhgCAYidrclDWaM3so9bfzZpuUenKtP74QNH6B');

echo $tiny->to(5);
// E
Expand All @@ -39,47 +38,59 @@ echo $tiny->to(126);

echo $tiny->from('XX');
// 126
```

echo $tiny->to(999);
// vk
## Character set rules

echo $tiny->from('vk');
// 999
Your alphabet must:

```
- contain at least 2 characters
- only contain unique characters
- stay fixed forever once you start issuing encoded IDs

## Configuration
Tiny throws an exception when the alphabet is invalid or when you try to decode characters that are not in the configured alphabet.

You must instanciate a new instance of Tiny with a random alpha-numeric set where each character must only be used exactly once. Do **NOT** change this once you start using Tiny, as you won't be able to reverse.
## Generate an alphabet

You can generate a random set from the commandline with `$ ./bin/genset`
After installing dependencies, generate a fresh 62-character alphabet with:

## Using laravel?
```bash
./bin/genset
```

If you're using laravel and want to use a more laravel-like and cleaner syntax you only have to follow these steps.
You can also generate one in code:

First open your ``app/config/app.php`` file and scroll down to your providers and add
```php
'providers' => array(
...
'ZackKitzmiller\TinyServiceProvider',
)
```
and then this to aliases
```php
'aliases' => array(
...
'Tiny' => 'ZackKitzmiller\Facades\Tiny',
)
$set = \ZackKitzmiller\Tiny::generateSet();
```

Lastly you run ``php artisan config:publish zackkitzmiller/tiny`` to publish the configuration file and then run ``php artisan tiny:generate`` to create a valid key.
The legacy `Tiny::generate_set()` helper is still available for backwards compatibility.

### Usage in Laravel
```php
echo Tiny::to(999);
// echos vk
This release does introduce a package-level modernization break: Composer autoloading now uses PSR-4 for `ZackKitzmiller\\` classes, so consumers relying on older PSR-0-era assumptions should verify their integration when upgrading.

The Laravel integration classes continue to autoload from the `ZackKitzmiller\\Laravel5\\` namespace under `src/ZackKitzmiller/Laravel5/`.

## Development

echo Tiny::from('E');
// echos 5
```bash
composer install
composer test
composer check
```

## Legacy Laravel integration

The repository still includes the original Laravel integration classes for older applications, but the package is now centered on the framework-agnostic core library.

For Laravel integration:

- Laravel 5+:
- register `ZackKitzmiller\Laravel5\TinyServiceProvider`
- optionally register the `ZackKitzmiller\Facades\Tiny` facade alias
- publish the config with `php artisan vendor:publish --tag=tiny-config`
- set `TINY_KEY` in your environment or run `php artisan tiny:generate`
- older Laravel integrations:
- register `ZackKitzmiller\TinyServiceProvider`
- optionally register the `ZackKitzmiller\Facades\Tiny` facade alias
- publish the package configuration with the framework command your app version expects
- run `php artisan tiny:generate` to persist the generated key
9 changes: 3 additions & 6 deletions bin/genset
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
#!/usr/bin/env php
<?php declare(strict_types=1);

<?php

$path = dirname(__FILE__);

include $path . '/../src/ZackKitzmiller/Tiny.php';
require dirname(__DIR__) . '/vendor/autoload.php';

echo "Generating TinyPHP Random Set...\n";

$set = \ZackKitzmiller\Tiny::generate_set();
$set = \ZackKitzmiller\Tiny::generateSet();

echo "Set Generated\n";
echo "Set: {$set} \n\n";
44 changes: 39 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
{
"name": "zackkitzmiller/tiny",
"description": "A reversible base62 ID obfuscater.",
"description": "A reversible base62-style ID obfuscator for modern PHP applications.",
"type": "library",
"license": "MIT",
"keywords": [
"base62",
"ids",
"obfuscation",
"php",
"tiny"
],
"homepage": "https://github.com/zackkitzmiller/tiny-php",
"authors": [
{
"name": "Jacob DeHart"
Expand All @@ -14,14 +23,39 @@
"email": "zack@inrpce.com"
}
],
"support": {
"issues": "https://github.com/zackkitzmiller/tiny-php/issues",
"source": "https://github.com/zackkitzmiller/tiny-php"
},
"require": {
"php": ">=5.3.0"
"php": "^8.1"
},
"require-dev": {
"phpunit/phpunit": "~3.7.0",
"league/phpunit-coverage-listener": "~1.1"
"phpunit/phpunit": "^10.5 || ^11.5"
},
"autoload": {
"psr-0": {"ZackKitzmiller": "src/"}
"psr-4": {
"ZackKitzmiller\\Laravel5\\": "src/ZackKitzmiller/Laravel5/",
"ZackKitzmiller\\": "src/ZackKitzmiller/"
}
},
"autoload-dev": {
"classmap": [
"tests/"
]
},
"bin": [
"bin/genset"
],
"scripts": {
"test": "phpunit",
"test:coverage": "phpunit --coverage-text",
"check": [
"@composer validate --strict",
"@test"
]
},
"config": {
"sort-packages": true
}
}
37 changes: 1 addition & 36 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,43 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit colors="true" bootstrap="vendor/autoload.php">
<phpunit bootstrap="vendor/autoload.php" colors="true">
<testsuites>
<testsuite name="Tiny Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-clover" target="build/coverage.xml"/>
</logging>
<filter>
<whitelist>
<file>src/ZackKitzmiller/Tiny.php</file>
</whitelist>
</filter>
<listeners>
<listener class="League\PHPUnitCoverageListener\Listener">
<arguments>
<array>
<element key="printer">
<object class="League\PHPUnitCoverageListener\Printer\StdOut"/>
</element>
<element key="hook">
<object class="League\PHPUnitCoverageListener\Hook\Travis"/>
</element>
<element key="namespace">
<string>ZackKitzmiller</string>
</element>
<element key="repo_token">
<string>4GggSuZVGvVaxBi8E9IZTqG31EXFvjMe7</string>
</element>
<element key="target_url">
<string>https://coveralls.io/api/v1/jobs</string>
</element>
<element key="coverage_dir">
<string>build/</string>
</element>
</array>
</arguments>
</listener>
</listeners>
</phpunit>
51 changes: 51 additions & 0 deletions src/ZackKitzmiller/EnvironmentKeyUpdater.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace ZackKitzmiller;

final class EnvironmentKeyUpdater
{
public const PRIMARY_KEY = 'TINY_KEY';

public const LEGACY_KEY = 'LEAGUE_TINY_KEY';

public static function updateContents(string $contents, string $key): string
{
$trimmed = rtrim($contents);
$primaryPattern = '/^[ \t]*' . self::PRIMARY_KEY . '=.*$/m';
$legacyPattern = '/^[ \t]*' . self::LEGACY_KEY . '=.*$/m';

if (preg_match($primaryPattern, $contents) === 1) {
$updated = preg_replace_callback(
$primaryPattern,
static fn (): string => self::PRIMARY_KEY . '=' . $key,
$contents,
1
);

if ($updated !== null) {
return $updated;
}
}

if (preg_match($legacyPattern, $contents) === 1) {
$updated = preg_replace_callback(
$legacyPattern,
static fn (): string => self::PRIMARY_KEY . '=' . $key,
$contents,
1
);

if ($updated !== null) {
return $updated;
}
}

if ($trimmed === '') {
return self::PRIMARY_KEY . '=' . $key . PHP_EOL;
}

return $trimmed . PHP_EOL . self::PRIMARY_KEY . '=' . $key . PHP_EOL;
}
}
Loading