arefshojaei/lite-php
Composer 安装命令:
composer create-project arefshojaei/lite-php
包简介
Micro PHP Framework
关键字:
README 文档
README
🔥 Lite-PHP | Micro Framework 🔥
A modern, elegant PHP directory listing application with file browsing, file viewing, and file downloading capabilities. Built with a beautiful UI using Tailwind CSS and JavaScript for an interactive experience.
✨ Features
Lightweight and fast development environment
Functional programming architecture (No classes & OOP)
Modular project structure
MySQL database support
Custom hooks and plugins
Command-line interface (CLI)
REST API development
Custom template engine
Testing system
Environment configuration support
📦 Installation & Setup
Requirements
- PHP 8.0 or higher
- Composer
Install using Composer
composer create-project arefshojaei/lite-php my-app
Move into your project:
cd my-app
Clone from GitHub
git clone https://github.com/ArefShojaei/Lite-PHP.git
cd Lite-PHP
Install dependencies:
composer install
📚 Tutorial :
- Flow chart of process
- Folder Structure
- Root Files
- Modules
- Template Engine
- Cli ( console )
- Helpers
- Hooks
- useHTTP
- useGET
- usePOST
- useFetch
- useID
- useConfig
- useEnum
- useState
- useGlobal
- useHash
- usePasswordVerfiy
- useHTML
- useMode
- useEnv
- useLog
- useError
- usePlugin
- useQuery
- useResponse
- useRequest
- useRedirect
- useURL
- useBody
- useHeader
- useMatch
- useFlash
- useFile
- useUpload
- useCache
- useCookie
- useSession
- useToken
- useVerifyToken
- useValidator
- useAction
- useTable
- useRecord
View of LITE PHP process in application
Folder Structure
Here is default folder structure for starting new project !
|- bootstrap/ | |- console/ | |- core/ | |- hooks/ | |- migrations/ | |- modules/ | |- plugins/ | |- public/ | |- resources/ | |- storage/ | | |- .env.example |- .gitignore |- .htaccess |- cli |- composer.json |- gulpfile.mjs |- init |- package.json |- README.md |- robots.txt |- server.php
core/
Main files or Lite-PHP core files that can be provided base files for every projects!
bootstrap/
Base files to boot the app
modules/
Modules that the app needs to run as main file
hooks/
Lets you to development custom hooks
migrations/
Lets you to work with database
plugins/
Lets you to development custom plugin
public/
Static files in production with entry point file ( index.php )
resources/
Asset and View files
storage/
Local folder & files like Log, Cache & Upload ...
Root Files
.env.example
This is a config for ENV , Then before starting the project you must changed it from .env.example to .env file!
.gitignore
This is a config to hide files to not push on Github
.htaccess
Apache web server config
cli
Console configuration to use commands
composer.json
Passport of package info
gulpfile.mjs
Task-runner configuration for assets
init
Basic setup configuration to development app
package.json
List of pacakge dependencies that the Task-runner needs to run
README.md
Lite-PHP Package info
robots.txt
This is configuration for crawlers of Google
server.php
Main file for launching the app
Modules
Alias
Registers custom Alias
1-Example:
# Before require_once "../../../modules/user/_controller.php"; require_once "../console/commands/package/_main.php"; # After + without using '.php' ext import("@modules/user/_controller") import("@commands/package/_main")
2-How can I use that ?
Move to "bootstrap/alias.php" Then, register an Alias by this way :
createAlias([ # Guide "@<alias>" => dirname(__DIR__) . "path", # Example "@core" => dirname(__DIR__) . "/core", "@modules" => dirname(__DIR__) . "/modules", ... ]);
Config
Registers new configuration for a module
1-How can I create a config ?
import("@core/modules/config/createConfig"); createConfig("name", [ "key" => "value" ]);
2-How can I use the config ?
import("@core/hooks/useConfig"); # Usage useConfig("name.key");
Enum
Registers an Enum as constant
1-How can I create an Enum ?
import("@core/modules/enum/createEnum"); createEnum("name", [ "KEY" => "value" ]);
2-How can I use the Enum ?
import("@core/hooks/useEnum"); # Usage useEnum("name::KEY");
Migration
Registers a Migration
1-How can I create a Migration ?
php cli make:migration [migration-name]
import("@core/modules/migration/createMigration"); import("@core/helpers/migration"); createMigration("table-name", [ "up" => function(string $table) { column_id(...); column_string(...); }, "down" => function(string $table) { table_dropIfExists(...); }, ]);
2-How can I use the migration ?
php cli list
> php cli migrate
> php cli migrate [table-name]
> php cli migrate:reset
> php cli migrate:reset [table-name]
>
php cli migrate:refresh
> php cli migrate:refresh [table-name]
Plugin
Registers new Plugin
Note: We have two types for using plugin :
- Runner Type needs to register in "bootstrap/providers.php"
- Usage Type needs to use in function or logic code
1-How can I create a Runner type Plugin ?
import("@core/modules/plugin/createPlugin"); # Usage createPlugin("name", function ($params) {}, false);
2-How can I use the Runner Plugin ?
Move to "bootstrap/providers.php" , then use this way to register the Runner Plugin
"plugins" => [ # Usage registerPlugin("name"), # Examples registerPlugin("logger", ["level" => "short"]), registerPlugin("security"), registerPlugin("cors"), ],
3-How can I create a Usage type Plugin ?
import("@core/modules/plugin/createPlugin"); # Usage createPlugin("name", function () {});
4-How can I use the Usage Plugin ?
Note: for using the plugin, you should use this way
import("@core/hooks/usePlugin"); # Usage list(...) = usePlugin("name");
Validator
Defines Schema for input data
1-How can I create a Schema ?
import("@core/modules/validator/createValidator"); createValidator("post", [ "id" => [ "type" => "int", "required" => true, ], "title" => [ "type" => "string", "min" => 20, ] ]);
2-How can I use that ?
import("@core/hooks/useValidator"); # Usage $schema = "post", $post = [ "id" => 1, "title" => "Thanks for using the Micro Framework.", ]; $isValid = useValidator($schema, $post);
Cli
These photos are demo of commands that can be done to develop your application!
Template Engine
Provides to work as professional with templates instead of using usual php template engine !
Examples :
Before - views/user.php
<?php foreach ($users as $user): ?> <div class="user-card"> <span>ID: <?php echo $user['id'] ?> </span> <h3>Name: <?php echo $user['name'] ?> </h3> <p>CV: <?php echo $user['cv'] ?> </p> </div> <?php endforeach; ?>
After - views/user.hbs
@foreach ($users as $user)
<div class="user-card">
<span>ID: {{ $user['id'] }} </span>
<h3>Name: {{ $user['name'] }} </h3>
<p>CV: {{ $user['cv'] }} </p>
</div>
@endforeach
NOTE: We want to work it as professional with customized .hbs template engine and we don't have this like JS lib ( handlebars ) template engine and you should know about it that we have a customized template engine !
Syntaxes
{{ $variable }} # to Protect XSS attack
{{{ $variable }}} # Not to Protect XSS attack
{{!-- comment message --}} # Writing Comment
Directives
Condition
# Directives
@if(expression)
@elseif
@else
@endif
{{!-- Example --}} @if ($role == 'manager') <h3>Welcome Manager</h3> @elseif ($role == 'admin') <h3>Welcome Admin</h3> @else <h3>The Role is not valid!</h3> @endif
Loop
# Directives
@foreach(expression)
@endforeach
@while(expression)
@endwhile
@break(expression)
@continue(expression)
{{!-- Example-1 --}} @foreach($users as $user) <div> <h3>Name: {{ $user['name'] }} </h3> <p>Email: {{ $user['email'] }} </p> </div> @endforeach {{!-- Example-2 --}} @while($count < 100) <p>Count: {{ $count }}</p> @countinue($count < 10) @break($count == 90) $count++; @endwhile
Partial
# Directives
@include(partialPath)
{{!-- Example --}} @include("includes.header") # include views/includes/header.hbs <h1>Welcome Page</h1> @include("includes.footer") # include views/includes/footer.hbs
Script
# Directives
@style
@endstyle
@linkStyle
@script
@endScript
@linkScript
@php
@endphp
@dump
@dd
{{!-- Example-1 --}} @style * { box-sizing: border-box; color : #e5e5e5; } @endStyle @linkStyle("https://domain.com/bootstrap/styles/grid.min.css") {{!-- Example-2 --}} @script const username = promt('Enter your userName:') alert(username) @endscript @linkScript("https://domain.com/jquery/jquery.min.css") {{!-- Example-3 --}} @php $message = "Welcome to Lite PHP" echo $message; @endphp {{!-- Example-4 --}} @dump($message, true, []) @dd([1,2,3,4,5])
Validation
# Directives
@isset(expression)
@endisset
@empty(expression)
@endempty
@flash(flash)
@endflash
{{!-- Example-1 --}} @isset($user['isCheckedRole']) <p>User role is checked</p> @endisset {{!-- Example-2 --}} @empty($posts) <p>Here we don't have any posts!</p> @endempty
CSRF token to protect attacks
# Directive
@csrf
<form> @csrf <input type="text" name="username" /> <input type="password" name="password" /> <button>Login</button> </form>
Auth
# Directives
@auth
@endauth
@authRole
@endauthRole
@guest
@endguest
{{!-- Example-1 --}} @auth <a href="...">Dashboard Panel</a> @endauth {{!-- Example-2 --}} @authRole("admin") <a href="...">Admin Dashboard</a> @endauthRole {{!-- Example-3 --}} @guest <a href="...">Login</a> <a href="...">Register</a> @endguest
Helpers
import
Loads file by Alias
import("@modules/user/_controller") $user = getUser(); print_r($user);
Route
Adds new Route in a module
Note: You can use it by two ways:
- Add Single Route
- Group Routes
- Sign Route
# Usage import("@core/helpers/route"); # Single Route addRoute("GET", "/user", "showUser"); # /user # Group Route groupRoute("/page", function() { addRoute("GET", "/", "__app__index"); # /page/home addRoute("GET", "/users", "__user__index"); # /page/users addRoute("GET", "/courses", "__course__index"); # /page/courses }); # Sign Route $secretKey = "..."; $route = addSignedRoute("/admin?pid=fk921", $secretKey, ....);
DD
Dumps and dies an Array in browser
Note : You don't need to load the helper, Because the helper has loaded !
$user = [ "id" => 1, "name" => "Robert", "skills" => ["PHP", ...] ]; # Usage dd($user); # to dump and die dd($user, false); # just to dump and no die process
Parse
Gets file content
import("@core/helpers/parse"); $file = "links.txt"; # Usage $links = prase($file); $links = @prase($file); # use the @ to get boolean or content if you don't want to get error forach ($links as $link) { echo "[Link] {$link}" . PHP_EOL; }
View
Renders view template
import("@core/helpers/view"); # Example 1 view("welcome"); # Example 2 $user = [ "id" => 267 "title" => "User Page", "name" => "Robert", ] view("user", $user);
Command
Adds new Command to use in console
Note: You can use it by two ways:
- Add Single Command
- Group Commands
# Usage import("@core/helpers/command"); # Single Command addCommand("database", fn() => "Hi from Lite PHP", "Database status"); # php cli database # Group Command groupCommand("fake:", function() { addCommand("city", "action", "description"); # php cli fake:city addCommand("company", "action", "description"); # php cli fake:company addCommand("user", "action", "description"); # php cli fake:user addCommand("book", "action", "description"); # php cli fake:book });
Test
Tests module
Note: You can test by two ways:
- Test single module by name
- Test all modules
# Usage import("@core/helpers/test"); # Definition describe('test-info', function() { it("test-description", function() { # use Asserts ... # Read "core/helpers/assertion.php" to use in this logic code ! }); }); # Usage # Test All Modules php cli test # Test Single Module php cli test [module-name]
Abort
Throw HTTP error as Rendered page to show Error message
import("@core/helpers/abort"); # Usage function bootstrap() { abort(500, "Internal Server Error", ["package" => "LITE PHP"]); }
Build
Builds new path & URL
import("@core/helpers/build"); # Guide buildURL("/products"); # [pre defined => (host:port)] + route buildPath("/resources", "/lang/en/public"); # base path + path + file ext
Translate
Translates content
import("@core/helpers/translate"); # Text: Welcome message "Translated: " . __("welcome"); # پیام خوش آمد گویی # Text: Thanks :name for using :product "Translated: " . __("introduce", [ "name" => "رابرت", "product" => "This package" ]); # ممنون رابرت برای استفاده کردن از این پکیج
URL
Provides to use helper functions for URL, Route and ...
import("@core/helpers/url"); # Get base URL baseURL(); # Http://localhost:5000 # Get current route url(); # /product/257 # Get current url origin(); # Http://localhost:5000/product/257 # Build pointer Route to redirect to another route toRoute("/users"); # Http://localhost:5000/users # Bind route by name addRoute("GET", "/dashboard/admin/page/users", "__admin_user__edit", name: "user") route("users") # "/dashboard/admin/page/users"
Assets
Provides to use helper functions for Asset files
import("@core/helpers/assets"); # Get asset path asset("/css/grid.css"); # resources/assets/css/grid.css # CSS asset path asset("/css/grid.css"); # resources/assets/css/grid.css css("grid"); # resources/assets/css/grid.css # JS asset path asset("/js/state.js"); # resources/assets/js/state.js js("state"); # resources/assets/js/state.js # Image asset path img("user.jpeg"); # resources/assets/img/user.jpeg # Icon asset path icon("logo.svg"); # resources/assets/img/logo.svg
Validator
Provides to validate data
import("@core/helpers/validator"); # Email validation $email_1 = "Robert@gmail.com"; $email_2 = "Kevin@yahoo.com"; isEmail($email_1); # true isEmail($email_2); # false # URL validation $url_1 = "http://localhost:5000"; $url_2 = "/categories/mobile/54673124"; isURL($url_1); # true isURL($url_2); # false # Signed route validation $route = "/dashboard?pid=019231"; $secretKey = "..."; $isValidSignedRoute = validateSignedRoute($route, $secretKey);
Assert
Provides to assert data in unit test
-
Note: You must use it when you are writing tests that exists in every modules of app with _test.php file!
-
If you like to use more asserts, you should move to "core/helpers/assert.php" file
import("@core/helpers/asserts"); assertTrue(""); # false assertTrue("This is a message"); # true assertTrue(0); # false assertTrue(1); # true assertEmpty([]) # true assertEmpty([1,2,3]) # false # and more assert functions....
Hooks
Note: You should use hooks in logic code and don't use that outer of logic code!
UseHTTP
Provides to use http as $_SERVER super global
import("@core/hooks/useHTTP"); function inspectRequest() { $method = useHTTP("REQUEST_METHOD"); echo $method; # GET, POST, PUT, PATCH, DELETE }
UseGET
Provides to use $_GET super global
import("@core/hooks/useGET"); function inspectRequest() { $username = useGET("username"); $password = useGET("password"); dd([ "username" => $username, "password" => $password ]); }
UsePOST
Provides to use $_POST super global
import("@core/hooks/usePOST"); function inspectRequest() { $token = usePOST("token"); echo $token; }
UseFetch
Provides to send http request
Examples :
# Send GET Request import("@core/hooks/useFetch"); $response = useFetch("http://domain.com/end-point"); dd($response);
# Send POST Request import("@core/hooks/useFetch"); $params = [ "method" => "POST", "body" => [], "headers" => [], ]; $response = useFetch("http://domain.com/end-point", $params); dd($response);
# Send PUT Request import("@core/hooks/useFetch"); $params = [ "method" => "PUT", "body" => [], "headers" => [], ]; $response = useFetch("http://domain.com/end-point", $params); dd($response);
# Send PATCH Request import("@core/hooks/useFetch"); $params = [ "method" => "PATCH", "body" => [], "headers" => [], ]; $response = useFetch("http://domain.com/end-point", $params); dd($response);
# Send DELETE Request import("@core/hooks/useFetch"); $params = [ "method" => "DELETE", "body" => [], "headers" => [], ]; $response = useFetch("http://domain.com/end-point", $params); dd($response);
UseID
Provides to get random number ID
import("@core/hooks/useID"); function createUser($name, $email, $passowrd) { $id = useID(); # logic code ... }
UseConfig
Provides to get Config by key
Note: Sometimes you don't want to get error for getting value from the hook usage, First you should load target module configuration in current file or script !
import("@core/hooks/useConfig"); function createUser($name, $email, $passowrd) { $applicationName = useConfig("app.name"); # logic code ... }
UseEnum
Provides to get Enum by key
Note: sometimes you dont' want to get error for getting value from the hook usage, First you should load target module configuration in current file or script !
import("@core/hooks/useEnum"); function createUser($name, $email, $passowrd) { # User SQL Table $userTable = useEnum("User::TABLE"); # HTTP Statuses $HTTP_200 = useEnum("HTTP::OK"); $HTTP_201 = useEnum("HTTP::SUCCESS"); $HTTP_400 = useEnum("HTTP::BAD"); # logic code ... }
UseState
Provides to define state in container as $GLOBALS['container'] super global
Note: The hook has more option that you will like that
- Define state as "value"
- Define state as "key" & "value"
- Define state as "key" (Nested) & "value"
import("@core/hooks/useState"); function createUser($id, $name, $email, $password) { $user = [ "email" => $email, "password" => $password ]; # First way => key & value useState("users", $user); # Second way => nested keys & value useState("users.{$name}", $user); # Third way => nested keys & value useState("users.{$id}.{$name}", $user); # logic code ... }
UseGlobal
Provides to get value from container as $GLOBALS['container'] super global
import("@core/hooks/useGlobal"); function getPlugins() { # First way => without nested key $plugins = useGlobal("plugins"); # $GLOBALS['container']['plugins'] # Second way => with nested keys $runnerPlugins = useGlobal("plugins.runner"); # $GLOBALS['container']['plugins']['runner'] $usagePlugins = useGlobal("plugins.usage"); # $GLOBALS['container']['plugins']['usage'] # logic code ... }
UseHash
Provides to hash password
import("@core/hooks/useHash"); function createUser($name, $email, $passowrd) { $hashedPassword = useHash($password); # logic code ... }
UseVerifyPassword
Provides to verify hashed password
import("@core/hooks/useVerifyPassword"); function checkPassword($password, $hashedPassowrd) { $isValidPassword = useVerifyPassword($password, $hashedPassword); # logic code ... }
UseHTML
Provides to get html content by url
import("@core/hooks/useHTML"); function getSiteHtmlContent($url) { $html = useHTML($url); # logic code ... }
UseMode
Provides to get current app mode from ".env" as APP_MODE ( Production | Development )
import("@core/hooks/useMode"); function getApplicationModeStatus() { $mode = useMode(); # Production | Development # logic code ... }
UseEnv
Provides to get env from ".env" by key
import("@core/hooks/useEnv"); function createDatabaseConnection() { $db = useEnv("DATABASE_DB"); $host = useEnv("DATABASE_HOST"); $username = useEnv("DATABASE_USER"); $password = useEnv("DATABASE_PASS"); # logic code ... }
UseLog
Provides to put log message
import("@core/hooks/useLog"); function showDashboardPage() { useLog("Admin Logged in!"); # logic code ... }
UsePlugin
Provides to use plugins that has usage type
import("@core/hooks/usePlugin"); function getShortLink($longURL) { [...] = usePlugin("shortLink"); # logic code ... }
UseQuery
Provides to run SQL query
import("@core/hooks/useQuery"); function createUser($name, $email, $passowrd) { useQuery("INSERT INTO `users` (name, email, password) VALUES (?, ?, ?)", [$name, $email, $passowrd]); # logic code ... } function doLogin($email, $passowrd) { $user = useQuery("SELECT * FROM `users` WHERE email = ?", [$email]); dd($user); # logic code ... }
UseResponse
Provides to return content output to the response as JSON | HTML | TEXT
Note : You don't need to set content-type in header, Because the hook has done it
- @Reference : core/hooks/useType
- @Reference : core/hooks/useResponse
import("@core/hooks/useResponse"); function showLoginPage() { $form = " <form action='' method='POST'> <input type='email' name='email' /> <input type='password' name='password' /> <button type='submit'>Login</button> </form> "; return useResponse("html", $form); }
UseRequest
Provides the request data
import("@core/hooks/useRequest"); function inspectRequest() { $host = useRequest("host"); # site.com $ip = useRequest("ip"); # 192.168.1.1 $method = useRequest("method"); # GET | POST | PUT | PATCH | DELETE $protocol = useRequest("protocol"); # HTTP | HTTPS $query = useRequest("query"); # LIKE /product/?category='mobile'&limit=10 $route = useRequest("route"); # /products $routeParams = useRequest("params"); # /product/{id} => ["id" => 171] $userAgent = useRequest("userAgent"); # ... # logic code ... }
UseRedirect
Provides to redirect to a route
import("@core/hooks/useRedirect"); function inspectRequest() { $isValidUser = true; if($isValidUser) { useRedirect("/dashboard"); } # logic code ... }
UseURL
Provides to parse URL
import("@core/hooks/useURL"); function inspectRequest() { $parsedURL = useURL("http://localhost:5000/api/v1/products/?limit=25"); dd($parsedURL); # logic code ... }
UseBody
Provides to get the request body data
import("@core/hooks/useBody"); function inspectRequest() { $token = useBody("token"); # logic code ... }
UseHeader
Provides to add & remove header by key and value
import("@core/hooks/useHeader"); function inspectRequest() { $fakeUserAgent = "..."; # add useHeader("HTTP_USER_AGENT", $fakeUserAgent); # remove useHeader("X-Powered-By"); # logic code ... }
UseMatch
Provides to use regex
import("@core/hooks/useMatch"); function isValidEmail($email) { $regexPattern = "/^\w+@gmail.com$/"; $result = useMatch($regexPattern, $email); dd($result); # logic code ... }
UseFlash
Provides to add & remove falsh message
import("@core/hooks/useFlash"); function doLogin() { useFlash("login", "Invalid Email or Password!"); # logic code ... }
useFile
Provides to get file from $_FILES
import("@core/hooks/useFile"); function addProfile() { $profile = useFile("profile"); # logic code ... }
useUpload
Provides to upload file in local stroage
import("@core/hooks/useFile"); import("@core/hooks/useUpload"); function uploadProfile() { $profile = useFile("profile"); $result = useUpload($profile); # logic code ... }
useCache
Provides to cache data
import("@core/hooks/useCache"); # Cache Data function cachePostsData() { $posts = [...]; useCache("posts", $posts); # logic code ... } # Get cached data function getCachedPostsData() { $posts = useCache("posts"); # logic code ... }
useCookie
Provides to use cookie in process of app
import("@core/hooks/useCookie"); # Set cookie useCookie("darkMode", true); # Get the cookie $darkModeState = useCookie("darkMode"); # true # Set cookie params useCookie("darkMode", rand(), [ "expireTime" => "", "path" => "", "domain" => "", "secure" => "", "httpOnly" => "" ]);
useSession
Provides to use session in process of app
import("@core/hooks/useSession"); # Set session useSession("isLoggedIn", true); # Get the session $loginState = useSession("isLoggedIn"); # true # Get list of all sessions $sessions = useSession();
UseToken
Provides to generate new token
import("@core/hooks/useToken"); function doLogin() { $user = [ "username" => "Robert", "password" => 12345 ]; $token = useToken($user, "secretKey"); # logic code ... }
UseVerifyToken
Provides to verify token
import("@core/hooks/useVerifyToken"); function exportLogs() { $token = "..."; $isValidUser = useVerifyToken($token,"secretKey"); # logic code ... }
useValidator
Provides to validate input data
import("@core/hooks/useValidator"); function validatePost() { $schema = "post"; $post = [ "id" => 1, "title" => "What is LITE PHP?", "body" => "Micro PHP Freamework!" ]; $isValid = useValidator($schema, $post); # logic code ... }
useAction
Provides to save action in local database
import("@core/hooks/useAction"); function addTodo() { useAction("ADD_TODO"); $todo = [ "id" => rand(), "title" => "Done login page", "timestamp" => time() ]; # logic code ... }
useRecord
Provides to save data in local database
import("@core/hooks/useRecord"); function addTodo() { $todo = [ "id" => rand(), "timestamp" => time() ]; useRecord("todos", $todo["title"], $todo["timestamp"]); # logic code ... }
useTable
Provides to get & delete data in local database
1-Getting data:
import("@core/hooks/useTable"); function getTimestamp() { $result = useTable('actions', 'NEW_TASK'); # Logic code ... }
2-Deleteing data:
import("@core/hooks/useTable"); function deleteAction() { $result = useTable('actions', 'NEW_TASK', $action = TABLE_DELETE_ACTION); # Logic code ... }
👨💻 Author
Aref Shojaei
- 📧 Email: arefshojaei82@gmail.com
- 🐙 GitHub: @ArefShojaei
- 📦 Packagist: arefshojaei/lite-php
⭐ Show Your Support
If this project helps you understand web crawling, HTML parsing, and DOM manipulation, consider giving it a Star ⭐ on GitHub.
Your support motivates future improvements.
统计信息
- 总下载量: 11
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 7
- 点击次数: 5
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2024-05-29