??使用Hashids將數(shù)字ID生成類似YouTube的ID或B站BVID

v0.0.1
版本
2023-08-01
版本更新時(shí)間
1044
安裝
5
star
webman-hashids
- Webman 中使用 Hashids 用于將數(shù)字ID生成類似YouTube的ID。當(dāng)您不想向用戶公開(kāi)數(shù)據(jù)庫(kù)數(shù)字ID時(shí)使用
- 支持B站的ID生成模式,生成B站/video/
BV1fx411v7eo
這種ID
安裝
composer require isszz/webman-hashids
配置
在 config/plugin/isszz/webman-hashids/app.php 中更改
return [
'enable' => true,
// 默認(rèn)連接名稱
'default' => 'main', // 支持bilibili的BV模式
// Hashids modes
'modes' => [
'main' => [
'salt' => '',
'length' => 0,
'alphabet' => 'oqyei4pYnjDLXuPOw6c9IvzlWUmBs1Z0rdAkFCKM8hgHb2QV7NJ35TfaxRtESGArray'
],
'other' => [
'salt' => 'salt',
'length' => 0,
'alphabet' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
],
'bilibili' => [
// 此模式無(wú)需添加其他的配置
// 前綴超過(guò)2位英文字母忽略
'prefix' => '', // B站BV模式前綴類似: BV1fx411v7eo = 12345678
],
],
];
用法
依賴注入方式
use isszz\hashids\Hashids;
class Index
{
public function index(Hashids $hashids)
{
// B站BV模式, B站模式支持第二個(gè)參數(shù)增加前綴,可以設(shè)置例如: prefix = 'BV'
$_hashids = $hashids->mode(name: 'bilibili');
$_hashids->encode(12345678); // 1fx411v7eo
$_hashids->decode('1fx411v7eo'); // 12345678
// other模式
$hashids->mode('other')->encode(12345678); // gpyAoR
$hashids->mode('other')->decode('gpyAoR'); // 12345678
// 默認(rèn)
$hashids->encode(12345678); // 1rQ2go
$hashids->decode('1rQ2go'); // 12345678
// 其他傳輸ID的方式,返回為數(shù)組,對(duì)應(yīng)傳參
$hashID = $hashids->encode(12, 34, 56, 78); // nyILSjosbR
$hashID2 = $hashids->encode([12, 34, 56, 78]); // nyILSjosbR
$result = $hashids->decode($hashID);
// 返回?cái)?shù)組
/*
$result = [
'0' => 12
'1' => 34
'2' => 56
'3' => 78
];
*/
}
}
facade方式引入
use isszz\hashids\facade\Hashids;
class Index
{
public function index()
{
// B站BV模式
Hashids::mode('bilibili')->encode(12345678); // 1fx411v7eo
Hashids::mode('bilibili')->decode('1fx411v7eo'); // 12345678
// other模式
Hashids::mode('other')->encode(12345678); // gpyAoR
Hashids::mode('other')->decode('gpyAoR'); // 12345678
// 默認(rèn)
Hashids::encode(12345678); // 1rQ2go
Hashids::decode('1rQ2go'); // 12345678
}
}
助手函數(shù)
class Index
{
public function index()
{
// 加密
id_encode(12345678); // 1rQ2go
id_encode(12, 34, 56, 78, 'other'); // nyILSjosbR
id_encode([12, 34, 56, 78], mode: 'other'); // nyILSjosbR
// 解密
id_decode('1rQ2go'); // 12345678
id_decode('gpyAoR', 'other'); // 12345678
// 切換模式
id_mode('other')->encode(12345678); // gpyAoR
id_mode('other')->decode('gpyAoR'); // 12345678
// 助手函數(shù)還有一個(gè)獲取字母表的函數(shù)
// 拿到可以用來(lái)設(shè)置`config/plugin/isszz/webman-hashids/app.php `配置中的alphabet字段
$alphabet = id_build_alphabet();
}
}
使用ThinkORM獲取器對(duì)ID進(jìn)行加密
public function getIdAttr($value)
{
return id_encode($value);
}
// 主鍵非id時(shí), 比如是tid時(shí)
public function getTidAttr($value)
{
return id_encode($value);
}
使用Laravel Eloquent ORM訪問(wèn)器對(duì)ID進(jìn)行加密
// 10.x版本
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected function id(): Attribute
{
return Attribute::make(
get: fn (int $value) => id_encode($value),
);
}
}
// 8.x版本
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function getIdAttribute($value)
{
return id_encode($value);
}
}
Request請(qǐng)求中的使用案例
新建一個(gè)路由中間件,在需要的路由引入,不需要解密的路由不建議引入
<?php
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
class Hashid implements MiddlewareInterface
{
public function process(Request $request, callable $next): Response
{
$parameters = [];
$route = $request->route;
if ($route) {
$parameters = $route->param() ?: [];
foreach ($parameters as $k => $v) {
$parameters[$k] = $this->decodeParam($v) ?: $v;
}
$route->setParams($parameters);
}
// POST + GET 用data傳值,因官方?jīng)]有對(duì)參數(shù)進(jìn)行二次修改的方法只有這樣啦,不過(guò)也挺好用的
$parameters = $request->all();
if ($parameters && count($parameters) > 0) {
foreach ($parameters as $k => $v) {
$parameters[$k] = $this->decodeParam($v) ?: $v;
}
$request->data = $parameters;
}
return $next($request);
}
private function decodeParam($value)
{
if (!preg_match("/^[0-9a-zA-Z@]+$/", $value)) {
return null;
}
// 切換模式
if (str_contains($value, '@')) {
[$value, $type] = explode('@', $value);
}
try {
return id_decode($value, $type ?? '') ?: null;
} catch(\Exception $e) {}
return null;
}
}
修改support\Request.php
增加如下方法
class Request extends \Webman\Http\Request
{
/**
* 獲取中間件中,以data參數(shù)傳遞的get或者post參數(shù),通常此方法獲取的是經(jīng)過(guò)中間件處理后的參數(shù)
*
* @param string|array|null $name
* @param mixed $default
* @return mixed|null
*/
public function data(string|array|null $name = null, $default = null)
{
$data = $this->data ?: [];
if(is_null($name)) {
return $data;
}
$result = [];
if(is_array($name) && count($data) > 0) {
foreach ($name as $key => $val) {
if (is_int($key)) {
$default = null;
$key = $val;
if (!key_exists($key, $data)) {
continue;
}
} else {
$default = $val;
}
$result[$key] = $data[$key] ?? $default;
}
return $result;
}
return $data[$name] ?? $default;
}
/**
* 從路由中獲取參數(shù)
*
* @param string|array|null $name
* @param mixed $default
* @return mixed|null
*/
public function route(string|array|null $name = null, $default = null)
{
$data = $this->route->param() ?: [];
if(is_null($name)) {
return $data;
}
$result = [];
if(is_array($name) && count($data) > 0) {
foreach ($name as $key => $val) {
if (is_int($key)) {
$default = null;
$key = $val;
if (!key_exists($key, $data)) {
continue;
}
} else {
$default = $val;
}
$result[$key] = $data[$key] ?? $default;
}
return $result;
}
return $data[$name] ?? $default;
}
}
控制器中使用例如
class TestController
{
public function index(Request $request)
{
// 正常的參數(shù)傳遞
// /test?id=1rQ2go&uid=daVBjxW@other
$request->data(['uid', 'id']);
$request->data('id');
$request->data('uid');
// 使用路由定義的參數(shù)
// /test/{id}/user/{uid}
// 官方的方法可以這樣一次一個(gè)參數(shù)拿
$request->route->param('uid');
// 我們有對(duì)request增加一些方法比如,這樣可以批量拿
[$uid, $id] = $request->route(['uid', 'id']);
// 也可以
$uid = $request->route('uid', null);
// 其中參數(shù)中以@分割,前面是要解析的參數(shù),后面的是以那種模式解析
return 'end';
}
}
- 基礎(chǔ)庫(kù)來(lái)自: vinkla/hashids