├── .env_example
├── .gitignore
├── .htaccess
├── LICENSE
├── README.md
├── composer.json
├── composer.lock
├── doc
├── 1.x_.env
├── 1.x_README.md
├── 1.x_esu.sql
├── 1.x_upgrade_2.x.md
└── 2.x_esu.sql
├── index.php
├── src
├── Cache.php
├── DB.php
├── EasyShortUrl.php
├── Exception
│ └── EasyShortUrlException.php
├── Helpers
│ ├── Constant.php
│ └── Functions.php
├── Router.php
└── WebAdmin.php
└── static
└── img.png
/.env_example:
--------------------------------------------------------------------------------
1 | # 短网址服务域名
2 | ESU_DOMAIN=http://s.lukachen.com
3 |
4 | # 数据库配置
5 | ESU_DB_HOST=127.0.0.1
6 | ESU_DB_DBNAME=esu
7 | ESU_DB_USERNAME=root
8 | ESU_DB_PASSWORD=root
9 | ESU_DB_PORT=3306
10 | ESU_DB_CHARSET=utf8
11 |
12 | # Redis 配置
13 | ESU_REDIS_DSN=tcp://127.0.0.1:6379
14 |
15 | # 是否开启缓存,可选项 0: 不开启, 1: 开启 (开启缓存,数据表跳转统计将失效)
16 | ESU_CACHE_OPEN=0
17 |
18 | # 缓存方式,可选项 Filesystem: 本地文件缓存, Redis: 缓存 (Redis 缓存,依赖 ESU_REDIS_DSN 配置)
19 | ESU_CACHE_CLIENT=Filesystem
20 |
21 | # 默认缓存时间 604800 秒 (1星期)
22 | ESU_CACHE_LIFETIME=604800
23 |
24 | # web_admin 页 access_key
25 | ESU_WEB_ADMIN_ACCESS_KEY=esu
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /ErrorFiles/
3 | .idea/
4 | .env
5 | u.php
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | RewriteEngine On
3 |
4 | RewriteBase /
5 |
6 | RewriteCond %{REQUEST_FILENAME} !-f
7 |
8 | RewriteCond %{REQUEST_FILENAME} !-d
9 |
10 | RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]
11 |
12 |
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 LukaChen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # easy-short-url 短网址 2.x
2 | - 使用方式: 可在 Laravel、Yii、ThinkPHP 等框架 Composer 包引入,也可以独立搭建短网址站点
3 | - 实现原理: id 自增(转自定义62进制)
4 | - 存储: MySQL
5 | - 缓存: 可在配置项 ESU_CACHE_OPEN、ESU_CACHE_CLIENT、ESU_CACHE_LIFETIME 定制
6 | - 安全: 转短网址、跳转长网址授权
7 |
8 | ## 导航
9 | - [1.x 版本](doc/1.x_README.md)
10 | - [1.x 升级 2.x 指南](doc/1.x_upgrade_2.x.md)
11 |
12 | ## 2.x 相比 1.x 新特性
13 | - 安全跳转,授权请求密钥、跳转域。基于安全考虑,跳转长网址域名,必须授权才可跳转
14 | - 缓存策略,可配置。可在配置项 ESU_CACHE_OPEN、ESU_CACHE_CLIENT、ESU_CACHE_LIFETIME 定制
15 |
16 | ## 使用步骤
17 | 1.获取包
18 | ```
19 | composer require chenlongqiang/easy-short-url "^2"
20 | ```
21 |
22 | 2.创建数据库
23 | ```
24 | mysql -u username -ppassword
25 | create database esu character set utf8 collate utf8_general_ci;
26 | ```
27 |
28 | 3.创建数据表
29 | ```
30 | mysql -u username -ppassword esu < doc/2.x_esu.sql
31 | ```
32 |
33 | 4.在项目根目录下,创建配置文件 .env
34 | ```
35 | cd 你的项目根目录
36 | cp ./vendor/chenlongqiang/easy-short-url/.env_example ./.env
37 | ```
38 |
39 | 5.vi .env 修改配置项
40 | ```
41 | # 短网址服务域名
42 | ESU_DOMAIN=http://s.lukachen.com
43 |
44 | # 数据库配置
45 | ESU_DB_HOST=127.0.0.1
46 | ESU_DB_DBNAME=esu
47 | ESU_DB_USERNAME=root
48 | ESU_DB_PASSWORD=root
49 | ESU_DB_PORT=3306
50 | ESU_DB_CHARSET=utf8
51 |
52 | # Redis 配置
53 | ESU_REDIS_DSN=tcp://127.0.0.1:6379
54 |
55 | # 是否开启缓存,可选项 0: 不开启, 1: 开启 (开启缓存,数据表跳转统计将失效)
56 | ESU_CACHE_OPEN=0
57 |
58 | # 缓存方式,可选项 Filesystem: 本地文件缓存, Redis: 缓存 (Redis 缓存,依赖 ESU_REDIS_DSN 配置)
59 | ESU_CACHE_CLIENT=Filesystem
60 |
61 | # 默认缓存时间 604800 秒 (1星期)
62 | ESU_CACHE_LIFETIME=604800
63 |
64 | # web_admin 页 access_key
65 | ESU_WEB_ADMIN_ACCESS_KEY=esu
66 | ```
67 |
68 | 6.授权请求密钥、跳转域名
69 | ```
70 | 在数据表 esu_access 添加数据即可
71 | ```
72 |
73 | ## 方法列表
74 | 1.生成短网址 toShort
75 | ```
76 | $shortUrl = \EasyShortUrl\EasyShortUrl::getInstance()->toShort('http://lukachen.com/archives/328/');
77 | ```
78 |
79 | 2.获取原网址 toLong
80 | ```
81 | $longUrl = \EasyShortUrl\EasyShortUrl::getInstance()->toLong($code);
82 | ```
83 |
84 | 完成以上步骤,即可在项目中引入本包,toShort、toLong 完成长短链接转化
85 | 如果不需要配置独立的转链网站,后面就不用看了 :)
86 |
87 | ## 需要搭建转链网站
88 | 需搭建类似 http://s.lukachen.com/web_admin 这样的网站,继续以下步骤(本项目已经提供前端页面,做好域名和服务器配置即可)
89 |
90 | 1.服务器配置
91 | ```
92 | 1) apache or nginx 配置 root 目录至 vendor/chenlongqiang/easy-short-url/
93 | 2) 配置 rewrite 重写至 index.php,不清楚的自行 baidu、google 或联系我
94 | ```
95 |
96 | 2.web页
97 | ```
98 | 地址: http://(你的短网址域名 ESU_DOMAIN 配置项)/web_admin
99 | 授权: web_admin 页,使用 ESU_WEB_ADMIN_ACCESS_KEY 配置项作为 access_key
100 | ```
101 |
102 | 3.api
103 | ```
104 | 地址: http://(你的短网址域名 ESU_DOMAIN 配置项)/api_gen
105 | 方法: POST
106 | 参数:
107 | type: to_short 或 to_long
108 | content: url
109 | access_key: api 授权密钥,可在 esu_access 新增
110 | ```
111 |
112 | 转链网站搭建完成 :)
113 |
114 | ## 我的短网址服务,体验地址
115 | http://s.lukachen.com/web_admin
116 |
117 | - 默认授权码 esu,已添加 lukachen.com 域名为合法跳转域,可用该跳转域名体验
118 | - 如长网址为:http://lukachen.com/friends 可缩短网址为 http://s.lukachen.com/LS
119 |
120 | ### 我的短网址,提供授权使用
121 | 需使用我搭建的短网址服务,请发邮件 365499684@qq.com 申请。跳转域名合理,我将会邮件回复授权码,并添加合法跳转域名
122 | 特别说明:
123 | - `我的短网址服务 s.lukachen.com` 不对微信业务开放,因为微信分享非常容易封禁域名,影响到大家使用
124 | - 使用本库自建服务,`自己决定跳转域名范围和使用场景`,键盘侠请自己睁大眼睛看清楚,懒得争论
125 |
126 | ### 我的短网址,申请模版
127 | ```
128 | 因 xxx 业务需要,申请短网址服务,跳转目标域名为
129 | lukachen.com
130 | google.com
131 | baidu.com
132 | ```
133 |
134 | ## 联系我
135 | - QQ: 365499684 (添加时请备注【短网址】)
136 | - Blog: http://lukachen.com/projects
137 | - 短网址 Demo 站点: http://s.lukachen.com/web_admin
138 | - 有疑问,欢迎 Issues
139 | - 有更棒的 Code 建议,欢迎 Pull Requests
140 | - 对你有帮助,请动动小手 Star Thank You :)
141 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chenlongqiang/easy-short-url",
3 | "description": "generate short url, use mysql.",
4 | "homepage": "https://github.com/chenlongqiang/easy-short-url",
5 | "type": "library",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "陈龙强",
10 | "email": "365499684@qq.com",
11 | "homepage": "http://lukachen.com"
12 | }
13 | ],
14 | "require": {
15 | "php": ">=5.6.0",
16 | "paragonie/easydb": "^1",
17 | "vlucas/phpdotenv": "^2.4",
18 | "symfony/cache": "3.4.47",
19 | "predis/predis": "^1.1"
20 | },
21 | "autoload": {
22 | "psr-4": {
23 | "EasyShortUrl\\": "src/"
24 | },
25 | "files": [
26 | "src/Helpers/Functions.php"
27 | ]
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "9baa3a0dab1ca7fb0f95618b1927a3e5",
8 | "packages": [
9 | {
10 | "name": "paragonie/easydb",
11 | "version": "v1.6.1",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/paragonie/easydb.git",
15 | "reference": "5372673ba5980dc94cc33e9d7d23e7df055a8632"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/paragonie/easydb/zipball/5372673ba5980dc94cc33e9d7d23e7df055a8632",
20 | "reference": "5372673ba5980dc94cc33e9d7d23e7df055a8632",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "ext-pdo": "*",
25 | "php": "^5.5|^7"
26 | },
27 | "require-dev": {
28 | "phpunit/phpunit": "^4|^5",
29 | "squizlabs/php_codesniffer": "^2.7"
30 | },
31 | "type": "library",
32 | "autoload": {
33 | "psr-4": {
34 | "ParagonIE\\EasyDB\\": "src"
35 | }
36 | },
37 | "notification-url": "https://packagist.org/downloads/",
38 | "license": [
39 | "MIT"
40 | ],
41 | "authors": [
42 | {
43 | "name": "Scott Arciszewski",
44 | "email": "scott@paragonie.com",
45 | "homepage": "https://paragonie.com",
46 | "role": "Developer"
47 | },
48 | {
49 | "name": "Woody Gilk",
50 | "homepage": "https://github.com/shadowhand",
51 | "role": "Contributor"
52 | },
53 | {
54 | "name": "SignpostMarv",
55 | "homepage": "https://github.com/SignpostMarv",
56 | "role": "Contributor"
57 | }
58 | ],
59 | "description": "Easy-to-use database abstraction",
60 | "keywords": [
61 | "database",
62 | "pdo",
63 | "security",
64 | "sql"
65 | ],
66 | "time": "2018-05-01T06:44:32+00:00"
67 | },
68 | {
69 | "name": "predis/predis",
70 | "version": "v1.1.6",
71 | "source": {
72 | "type": "git",
73 | "url": "https://github.com/predis/predis.git",
74 | "reference": "9930e933c67446962997b05201c69c2319bf26de"
75 | },
76 | "dist": {
77 | "type": "zip",
78 | "url": "https://api.github.com/repos/predis/predis/zipball/9930e933c67446962997b05201c69c2319bf26de",
79 | "reference": "9930e933c67446962997b05201c69c2319bf26de",
80 | "shasum": ""
81 | },
82 | "require": {
83 | "php": ">=5.3.9"
84 | },
85 | "require-dev": {
86 | "cweagans/composer-patches": "^1.6",
87 | "phpunit/phpunit": "~4.8"
88 | },
89 | "suggest": {
90 | "ext-curl": "Allows access to Webdis when paired with phpiredis",
91 | "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
92 | },
93 | "type": "library",
94 | "extra": {
95 | "composer-exit-on-patch-failure": true,
96 | "patches": {
97 | "phpunit/phpunit-mock-objects": {
98 | "Fix PHP 7 and 8 compatibility": "./tests/phpunit_mock_objects.patch"
99 | },
100 | "phpunit/phpunit": {
101 | "Fix PHP 7 compatibility": "./tests/phpunit_php7.patch",
102 | "Fix PHP 8 compatibility": "./tests/phpunit_php8.patch"
103 | }
104 | }
105 | },
106 | "autoload": {
107 | "psr-4": {
108 | "Predis\\": "src/"
109 | }
110 | },
111 | "notification-url": "https://packagist.org/downloads/",
112 | "license": [
113 | "MIT"
114 | ],
115 | "authors": [
116 | {
117 | "name": "Daniele Alessandri",
118 | "email": "suppakilla@gmail.com",
119 | "homepage": "http://clorophilla.net",
120 | "role": "Creator & Maintainer"
121 | },
122 | {
123 | "name": "Till Krüss",
124 | "homepage": "https://till.im",
125 | "role": "Maintainer"
126 | }
127 | ],
128 | "description": "Flexible and feature-complete Redis client for PHP and HHVM",
129 | "homepage": "http://github.com/predis/predis",
130 | "keywords": [
131 | "nosql",
132 | "predis",
133 | "redis"
134 | ],
135 | "funding": [
136 | {
137 | "url": "https://github.com/sponsors/tillkruss",
138 | "type": "github"
139 | }
140 | ],
141 | "time": "2020-09-11T19:18:05+00:00"
142 | },
143 | {
144 | "name": "psr/cache",
145 | "version": "1.0.1",
146 | "source": {
147 | "type": "git",
148 | "url": "https://github.com/php-fig/cache.git",
149 | "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
150 | },
151 | "dist": {
152 | "type": "zip",
153 | "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
154 | "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
155 | "shasum": ""
156 | },
157 | "require": {
158 | "php": ">=5.3.0"
159 | },
160 | "type": "library",
161 | "extra": {
162 | "branch-alias": {
163 | "dev-master": "1.0.x-dev"
164 | }
165 | },
166 | "autoload": {
167 | "psr-4": {
168 | "Psr\\Cache\\": "src/"
169 | }
170 | },
171 | "notification-url": "https://packagist.org/downloads/",
172 | "license": [
173 | "MIT"
174 | ],
175 | "authors": [
176 | {
177 | "name": "PHP-FIG",
178 | "homepage": "http://www.php-fig.org/"
179 | }
180 | ],
181 | "description": "Common interface for caching libraries",
182 | "keywords": [
183 | "cache",
184 | "psr",
185 | "psr-6"
186 | ],
187 | "time": "2016-08-06T20:24:11+00:00"
188 | },
189 | {
190 | "name": "psr/log",
191 | "version": "1.1.3",
192 | "source": {
193 | "type": "git",
194 | "url": "https://github.com/php-fig/log.git",
195 | "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
196 | },
197 | "dist": {
198 | "type": "zip",
199 | "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
200 | "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
201 | "shasum": ""
202 | },
203 | "require": {
204 | "php": ">=5.3.0"
205 | },
206 | "type": "library",
207 | "extra": {
208 | "branch-alias": {
209 | "dev-master": "1.1.x-dev"
210 | }
211 | },
212 | "autoload": {
213 | "psr-4": {
214 | "Psr\\Log\\": "Psr/Log/"
215 | }
216 | },
217 | "notification-url": "https://packagist.org/downloads/",
218 | "license": [
219 | "MIT"
220 | ],
221 | "authors": [
222 | {
223 | "name": "PHP-FIG",
224 | "homepage": "http://www.php-fig.org/"
225 | }
226 | ],
227 | "description": "Common interface for logging libraries",
228 | "homepage": "https://github.com/php-fig/log",
229 | "keywords": [
230 | "log",
231 | "psr",
232 | "psr-3"
233 | ],
234 | "time": "2020-03-23T09:12:05+00:00"
235 | },
236 | {
237 | "name": "psr/simple-cache",
238 | "version": "1.0.1",
239 | "source": {
240 | "type": "git",
241 | "url": "https://github.com/php-fig/simple-cache.git",
242 | "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
243 | },
244 | "dist": {
245 | "type": "zip",
246 | "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
247 | "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
248 | "shasum": ""
249 | },
250 | "require": {
251 | "php": ">=5.3.0"
252 | },
253 | "type": "library",
254 | "extra": {
255 | "branch-alias": {
256 | "dev-master": "1.0.x-dev"
257 | }
258 | },
259 | "autoload": {
260 | "psr-4": {
261 | "Psr\\SimpleCache\\": "src/"
262 | }
263 | },
264 | "notification-url": "https://packagist.org/downloads/",
265 | "license": [
266 | "MIT"
267 | ],
268 | "authors": [
269 | {
270 | "name": "PHP-FIG",
271 | "homepage": "http://www.php-fig.org/"
272 | }
273 | ],
274 | "description": "Common interfaces for simple caching",
275 | "keywords": [
276 | "cache",
277 | "caching",
278 | "psr",
279 | "psr-16",
280 | "simple-cache"
281 | ],
282 | "time": "2017-10-23T01:57:42+00:00"
283 | },
284 | {
285 | "name": "symfony/cache",
286 | "version": "v3.4.47",
287 | "source": {
288 | "type": "git",
289 | "url": "https://github.com/symfony/cache.git",
290 | "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813"
291 | },
292 | "dist": {
293 | "type": "zip",
294 | "url": "https://api.github.com/repos/symfony/cache/zipball/a7a14c4832760bd1fbd31be2859ffedc9b6ff813",
295 | "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813",
296 | "shasum": ""
297 | },
298 | "require": {
299 | "php": "^5.5.9|>=7.0.8",
300 | "psr/cache": "~1.0",
301 | "psr/log": "~1.0",
302 | "psr/simple-cache": "^1.0",
303 | "symfony/polyfill-apcu": "~1.1"
304 | },
305 | "conflict": {
306 | "symfony/var-dumper": "<3.3"
307 | },
308 | "provide": {
309 | "psr/cache-implementation": "1.0",
310 | "psr/simple-cache-implementation": "1.0"
311 | },
312 | "require-dev": {
313 | "cache/integration-tests": "dev-master",
314 | "doctrine/cache": "^1.6",
315 | "doctrine/dbal": "^2.4|^3.0",
316 | "predis/predis": "^1.0"
317 | },
318 | "type": "library",
319 | "autoload": {
320 | "psr-4": {
321 | "Symfony\\Component\\Cache\\": ""
322 | },
323 | "exclude-from-classmap": [
324 | "/Tests/"
325 | ]
326 | },
327 | "notification-url": "https://packagist.org/downloads/",
328 | "license": [
329 | "MIT"
330 | ],
331 | "authors": [
332 | {
333 | "name": "Nicolas Grekas",
334 | "email": "p@tchwork.com"
335 | },
336 | {
337 | "name": "Symfony Community",
338 | "homepage": "https://symfony.com/contributors"
339 | }
340 | ],
341 | "description": "Symfony Cache component with PSR-6, PSR-16, and tags",
342 | "homepage": "https://symfony.com",
343 | "keywords": [
344 | "caching",
345 | "psr6"
346 | ],
347 | "funding": [
348 | {
349 | "url": "https://symfony.com/sponsor",
350 | "type": "custom"
351 | },
352 | {
353 | "url": "https://github.com/fabpot",
354 | "type": "github"
355 | },
356 | {
357 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
358 | "type": "tidelift"
359 | }
360 | ],
361 | "time": "2020-10-24T10:57:07+00:00"
362 | },
363 | {
364 | "name": "symfony/polyfill-apcu",
365 | "version": "v1.20.0",
366 | "source": {
367 | "type": "git",
368 | "url": "https://github.com/symfony/polyfill-apcu.git",
369 | "reference": "f5191eb0e98e08d12eb49fc0ed0820e37de89fdf"
370 | },
371 | "dist": {
372 | "type": "zip",
373 | "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/f5191eb0e98e08d12eb49fc0ed0820e37de89fdf",
374 | "reference": "f5191eb0e98e08d12eb49fc0ed0820e37de89fdf",
375 | "shasum": ""
376 | },
377 | "require": {
378 | "php": ">=7.1"
379 | },
380 | "type": "library",
381 | "extra": {
382 | "branch-alias": {
383 | "dev-main": "1.20-dev"
384 | },
385 | "thanks": {
386 | "name": "symfony/polyfill",
387 | "url": "https://github.com/symfony/polyfill"
388 | }
389 | },
390 | "autoload": {
391 | "psr-4": {
392 | "Symfony\\Polyfill\\Apcu\\": ""
393 | },
394 | "files": [
395 | "bootstrap.php"
396 | ]
397 | },
398 | "notification-url": "https://packagist.org/downloads/",
399 | "license": [
400 | "MIT"
401 | ],
402 | "authors": [
403 | {
404 | "name": "Nicolas Grekas",
405 | "email": "p@tchwork.com"
406 | },
407 | {
408 | "name": "Symfony Community",
409 | "homepage": "https://symfony.com/contributors"
410 | }
411 | ],
412 | "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions",
413 | "homepage": "https://symfony.com",
414 | "keywords": [
415 | "apcu",
416 | "compatibility",
417 | "polyfill",
418 | "portable",
419 | "shim"
420 | ],
421 | "funding": [
422 | {
423 | "url": "https://symfony.com/sponsor",
424 | "type": "custom"
425 | },
426 | {
427 | "url": "https://github.com/fabpot",
428 | "type": "github"
429 | },
430 | {
431 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
432 | "type": "tidelift"
433 | }
434 | ],
435 | "time": "2020-10-23T14:02:19+00:00"
436 | },
437 | {
438 | "name": "vlucas/phpdotenv",
439 | "version": "v2.4.0",
440 | "source": {
441 | "type": "git",
442 | "url": "https://github.com/vlucas/phpdotenv.git",
443 | "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c"
444 | },
445 | "dist": {
446 | "type": "zip",
447 | "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c",
448 | "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c",
449 | "shasum": ""
450 | },
451 | "require": {
452 | "php": ">=5.3.9"
453 | },
454 | "require-dev": {
455 | "phpunit/phpunit": "^4.8 || ^5.0"
456 | },
457 | "type": "library",
458 | "extra": {
459 | "branch-alias": {
460 | "dev-master": "2.4-dev"
461 | }
462 | },
463 | "autoload": {
464 | "psr-4": {
465 | "Dotenv\\": "src/"
466 | }
467 | },
468 | "notification-url": "https://packagist.org/downloads/",
469 | "license": [
470 | "BSD-3-Clause-Attribution"
471 | ],
472 | "authors": [
473 | {
474 | "name": "Vance Lucas",
475 | "email": "vance@vancelucas.com",
476 | "homepage": "http://www.vancelucas.com"
477 | }
478 | ],
479 | "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
480 | "keywords": [
481 | "dotenv",
482 | "env",
483 | "environment"
484 | ],
485 | "time": "2016-09-01T10:05:43+00:00"
486 | }
487 | ],
488 | "packages-dev": [],
489 | "aliases": [],
490 | "minimum-stability": "stable",
491 | "stability-flags": [],
492 | "prefer-stable": false,
493 | "prefer-lowest": false,
494 | "platform": {
495 | "php": ">=5.6.0"
496 | },
497 | "platform-dev": [],
498 | "plugin-api-version": "1.1.0"
499 | }
500 |
--------------------------------------------------------------------------------
/doc/1.x_.env:
--------------------------------------------------------------------------------
1 | # 生成的短网址域名
2 | DOMAIN=http://s.lukachen.com
3 | # web 页 session 有效时间
4 | WEB_SESSION_LIFE=600
5 | # api ACCESS_KEY
6 | ACCESS_KEY=easy123456|short099876|url123567
7 |
8 | DB_HOST=127.0.0.1
9 | DB_DBNAME=esu
10 | DB_USERNAME=root
11 | DB_PASSWORD=root
12 |
13 | TABLE_URL=esu_url
--------------------------------------------------------------------------------
/doc/1.x_README.md:
--------------------------------------------------------------------------------
1 | # easy-short-url 短网址 1.x
2 | - 使用方式: 可在 laravel、yii、thinkphp 等框架 composer 包引入,也可以独立搭建短网址网站
3 | - 实现原理: id 自增(转自定义62进制)
4 | - 存储: mysql
5 | - 统计: 302 重定向, 数据库 request_num 字段统计(如考虑高并发的查询性能瓶颈,可自己在调用层做 redis or memcache 缓存,统计将失效)
6 |
7 | ## 使用步骤
8 |
9 | 1.获取包
10 | ```
11 | composer require chenlongqiang/easy-short-url ^1
12 | ```
13 |
14 | 2.创建数据库
15 | ```
16 | mysql -u username -ppassword
17 | create database esu character set utf8 collate utf8_general_ci;
18 | ```
19 |
20 | 3.创建数据表
21 | ```
22 | mysql -u username -ppassword esu < doc/1.x_esu.sql
23 | ```
24 |
25 | 4.在项目根目录下,创建配置文件 .env
26 | ```
27 | cd 你的项目根目录
28 | cp ./vendor/chenlongqiang/easy-short-url/.env_example ./.env
29 | ```
30 |
31 | 5.vi .env 修改配置项
32 | ```
33 | # 生成的短网址域名
34 | DOMAIN=http://s.lukachen.com
35 | # web 页 session 有效时间
36 | WEB_SESSION_LIFE=600
37 | # api ACCESS_KEY
38 | ACCESS_KEY=easy123456|short099876|url123567
39 |
40 | DB_HOST=127.0.0.1
41 | DB_DBNAME=esu
42 | DB_USERNAME=root
43 | DB_PASSWORD=root
44 |
45 | TABLE_URL=esu_url
46 | ```
47 |
48 | ## 方法列表
49 |
50 | 0.config
51 | ```
52 | $dbConfig = [
53 | 'host' => env('DB_HOST'),
54 | 'dbname' => env('DB_DBNAME'),
55 | 'username' => env('DB_USERNAME'),
56 | 'password' => env('DB_PASSWORD'),
57 | ];
58 | $options = [
59 | 'domain' => env('DOMAIN'),
60 | 'tableUrl' => env('TABLE_URL'),
61 | ];
62 | ```
63 |
64 | 1.生成短网址 toShort
65 | ```
66 | $shortUrl = \EasyShortUrl\EasyShortUrl::getInstance($dbConfig, $options)->toShort('http://lukachen.com/archives/328/');
67 | ```
68 |
69 | 2.获取原网址 toLong
70 | ```
71 | $longUrl = \EasyShortUrl\EasyShortUrl::getInstance($dbConfig, $options)->toLong($code);
72 | ```
73 |
74 | 完成以上步骤,即可在项目中引入本包,toShort、toLong 完成长短链接转化。
75 | 如果不需要配置独立的转链网站,后面就不用看了 :)
76 |
77 | ## 需要搭建转链网站
78 |
79 | 需搭建类似 http://s.lukachen.com/web_admin 这样的网站,继续以下步骤(本项目已经提供前端页面,做好域名和服务器配置即可)
80 |
81 | 1.服务器配置
82 | ```
83 | 1) apache or nginx 配置 root 目录至 vendor/chenlongqiang/easy-short-url/
84 | 2) 配置 rewrite 重写至 index.php,不清楚的自行 baidu、google 或联系我
85 | ```
86 |
87 | 2.web页(.env DOMAIN 改成自己的域名)
88 | ```
89 | 地址: http://(你的短网址域名)/web_admin
90 | 授权: web页自带 session_key 授权,session_key 有效期在 .env 中配置 WEB_SESSION_LIFE 单位秒
91 | ```
92 |
93 | 3.api
94 | ```
95 | 地址: http://(你的短网址域名)/api_gen
96 | 方法: POST
97 | 参数:
98 | type: to_short 或 to_long
99 | content: url
100 | access_key: api 授权 key 在 .env 中新增,多个 ACCESS_KEY 使用 | 分割
101 | ```
102 |
103 | ## 作者
104 | - QQ 365499684 (添加时备注【短网址】)
105 | - Blog http://lukachen.com
106 | - 短网址 http://s.lukachen.com/web_admin
107 | - 觉得对你有所帮助,请点个 star 谢谢 :)
108 |
--------------------------------------------------------------------------------
/doc/1.x_esu.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Navicat MySQL Data Transfer
3 | Source Server : lukachen
4 | Target Server Type : MYSQL
5 | Target Server Version : 50148
6 | Date: 2018-05-02 11:10:54
7 | */
8 |
9 | SET FOREIGN_KEY_CHECKS=0;
10 |
11 | -- ----------------------------
12 | -- Table structure for esu_url
13 | -- ----------------------------
14 | DROP TABLE IF EXISTS `esu_url`;
15 | CREATE TABLE `esu_url` (
16 | `id` int(11) NOT NULL AUTO_INCREMENT,
17 | `code` varchar(8) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '短网址code',
18 | `long_url` varchar(1024) NOT NULL DEFAULT '' COMMENT '长网址',
19 | `long_url_hash` varchar(32) NOT NULL DEFAULT '' COMMENT '长网址做hash后的值',
20 | `request_num` int(11) NOT NULL DEFAULT '0' COMMENT '请求次数',
21 | `ip` varchar(32) NOT NULL DEFAULT '' COMMENT '请求ip',
22 | `created_at` datetime NOT NULL COMMENT '创建时间',
23 | PRIMARY KEY (`id`)
24 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='长短网址对应表';
25 |
--------------------------------------------------------------------------------
/doc/1.x_upgrade_2.x.md:
--------------------------------------------------------------------------------
1 | # 1.x 升级 2.x 指南
2 |
3 | ## 1.备份当前数据表 esu_url、代码(如有问题,方便快速回滚)
4 |
5 | ## 2.根据 2.x .env 修改配置文件
6 | ```
7 | # 短网址服务域名
8 | ESU_DOMAIN=http://s.lukachen.com
9 |
10 | # 数据库配置
11 | ESU_DB_HOST=127.0.0.1
12 | ESU_DB_DBNAME=esu
13 | ESU_DB_USERNAME=root
14 | ESU_DB_PASSWORD=root
15 | ESU_DB_PORT=3306
16 | ESU_DB_CHARSET=utf8
17 |
18 | # Redis 配置
19 | ESU_REDIS_DSN=tcp://127.0.0.1:6379
20 |
21 | # 是否开启缓存,可选项 0: 不开启, 1: 开启 (开启缓存,数据表跳转统计将失效)
22 | ESU_CACHE_OPEN=0
23 |
24 | # 缓存方式,可选项 Filesystem: 本地文件缓存, Redis: 缓存 (Redis 缓存,依赖 ESU_REDIS_DSN 配置)
25 | ESU_CACHE_CLIENT=Filesystem
26 |
27 | # 默认缓存时间 604800 秒 (1星期)
28 | ESU_CACHE_LIFETIME=604800
29 |
30 | # web_admin 页 access_key
31 | ESU_WEB_ADMIN_ACCESS_KEY=esu
32 | ```
33 |
34 | ## 3.执行 SQL,添加数据表
35 | ```
36 | ALTER TABLE esu_url ADD COLUMN `access_key` VARCHAR ( 32 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '密钥' AFTER `ip`;
37 | ALTER TABLE esu_url ADD COLUMN `updated_at` datetime(0) NOT NULL COMMENT '更新时间';
38 | UPDATE esu_url SET updated_at = created_at;
39 |
40 | UPDATE esu_url SET access_key = 'esu';
41 |
42 | CREATE TABLE `esu_access` (
43 | `id` int(11) NOT NULL AUTO_INCREMENT,
44 | `access_key` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '密钥',
45 | `access_domain` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '可跳转域名',
46 | `created_at` datetime(0) NOT NULL COMMENT '创建时间',
47 | `updated_at` datetime(0) NOT NULL COMMENT '更新时间',
48 | PRIMARY KEY (`id`) USING BTREE
49 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '授权表' ROW_FORMAT = Dynamic;
50 |
51 | INSERT INTO `esu_access` VALUES (1, 'esu', 'lukachen.com', '2021-01-05 18:34:48', '2021-01-05 18:34:48');
52 | ```
53 |
54 | ## 4.添加授权数据
55 | 整理当前 esu_url 表中,需要跳转的域名
56 | ```
57 | INSERT INTO `esu_access`(`access_key`, `access_domain`, `created_at`, `updated_at`) VALUES ('esu', 'todo1.com', now(), now());
58 | INSERT INTO `esu_access`(`access_key`, `access_domain`, `created_at`, `updated_at`) VALUES ('esu', 'todo2.com', now(), now());
59 | INSERT INTO `esu_access`(`access_key`, `access_domain`, `created_at`, `updated_at`) VALUES ('esu', 'todo3.com', now(), now());
60 | ```
61 |
62 | ## 5.修改 composer.json 文件
63 | 修改版本号为 ^2
64 | ```
65 | "require": {
66 | "chenlongqiang/easy-short-url": "^2"
67 | }
68 | ```
69 |
70 | ## 6.执行 composer update 完成升级
--------------------------------------------------------------------------------
/doc/2.x_esu.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Navicat Premium Data Transfer
3 | Source Server Type : MySQL
4 | Date: 06/01/2021 10:54:34
5 | */
6 |
7 | SET FOREIGN_KEY_CHECKS = 0;
8 |
9 | -- ----------------------------
10 | -- Table structure for esu_url
11 | -- ----------------------------
12 | DROP TABLE IF EXISTS `esu_url`;
13 | CREATE TABLE `esu_url` (
14 | `id` int(11) NOT NULL AUTO_INCREMENT,
15 | `code` varchar(8) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '短网址code',
16 | `long_url` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '长网址',
17 | `long_url_hash` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '长网址做hash后的值',
18 | `request_num` int(11) NOT NULL DEFAULT 0 COMMENT '请求次数',
19 | `ip` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '请求ip',
20 | `access_key` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '密钥',
21 | `created_at` datetime(0) NOT NULL COMMENT '创建时间',
22 | `updated_at` datetime(0) NOT NULL COMMENT '更新时间',
23 | PRIMARY KEY (`id`) USING BTREE
24 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '长短网址对应表' ROW_FORMAT = Dynamic;
25 |
26 | -- ----------------------------
27 | -- Table structure for esu_access
28 | -- ----------------------------
29 | DROP TABLE IF EXISTS `esu_access`;
30 | CREATE TABLE `esu_access` (
31 | `id` int(11) NOT NULL AUTO_INCREMENT,
32 | `access_key` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '密钥',
33 | `access_domain` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '可跳转域名',
34 | `created_at` datetime(0) NOT NULL COMMENT '创建时间',
35 | `updated_at` datetime(0) NOT NULL COMMENT '更新时间',
36 | PRIMARY KEY (`id`) USING BTREE
37 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '授权表' ROW_FORMAT = Dynamic;
38 |
39 | -- ----------------------------
40 | -- Records of esu_access
41 | -- ----------------------------
42 | INSERT INTO `esu_access` VALUES (1, 'esu', 'lukachen.com', '2021-01-05 18:34:48', '2021-01-05 18:34:48');
43 |
44 | SET FOREIGN_KEY_CHECKS = 1;
45 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | load();
23 |
24 | (new EasyShortUrl\Router(trim($_SERVER['REQUEST_URI'], '/')))->dispatch();
--------------------------------------------------------------------------------
/src/Cache.php:
--------------------------------------------------------------------------------
1 | 'map_{code}',
54 | ];
55 |
56 | $find = $replace = [];
57 | foreach ($params as $k => $v) {
58 | $find[] = '{' . $k . '}';
59 | $replace[] = $v;
60 | }
61 | return str_replace($find, $replace, $mapping[$key]);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/DB.php:
--------------------------------------------------------------------------------
1 | validateAccess($accessKey, $longUrl);
54 |
55 | $longUrlHash = md5($longUrl . $accessKey);
56 |
57 | $existsCode = DB::getInstance()->single("SELECT code FROM esu_url WHERE long_url_hash = ?", [$longUrlHash]);
58 | if ($existsCode !== false) {
59 | return $this->buildShortUrl($existsCode);
60 | }
61 |
62 | $id = DB::getInstance()->insertReturnId('esu_url', [
63 | 'code' => '',
64 | 'long_url' => $longUrl,
65 | 'long_url_hash' => $longUrlHash,
66 | 'request_num' => 0,
67 | 'ip' => esu_get_ip(),
68 | 'access_key' => $accessKey,
69 | 'created_at' => date('Y-m-d H:i:s'),
70 | 'updated_at' => date('Y-m-d H:i:s'),
71 | ]);
72 |
73 | $code = $this->base10To62($id);
74 |
75 | DB::getInstance()->update('esu_url', ['code' => $code], ['id' => $id]);
76 |
77 | return $this->buildShortUrl($code);
78 | }
79 |
80 | /**
81 | * 短网址还原为长网址
82 | * short url restore long url
83 | * @param $code
84 | * @return bool
85 | */
86 | public function toLong($code)
87 | {
88 | $this->validateAccessByCode($code);
89 |
90 | $res = DB::getInstance()->row("SELECT id,long_url,request_num FROM esu_url WHERE code = ?", $code);
91 |
92 | return $res['long_url'];
93 | }
94 |
95 | /**
96 | * 跳转次数递增
97 | * redirect num ++
98 | * @param $code
99 | * @return bool
100 | */
101 | public function requestNum($code)
102 | {
103 | $res = DB::getInstance()->row("SELECT id,request_num FROM esu_url WHERE code = ?", $code);
104 | if (empty($res)) {
105 | return false;
106 | }
107 |
108 | DB::getInstance()->update('esu_url', [
109 | 'request_num' => $res['request_num'] + 1,
110 | 'updated_at' => date('Y-m-d H:i:s')
111 | ], ['id' => $res['id']]);
112 | return true;
113 | }
114 |
115 | /**
116 | * 10 进制数转自定义 62 进制数
117 | * decimal to custom 62 hex
118 | * @param $num
119 | * @return string
120 | */
121 | public function base10To62($num)
122 | {
123 | $res = '';
124 | while ($num > 0) {
125 | $res = substr(self::STR_SHUFFLE_62, $num % 62, 1) . $res;
126 | $num = floor($num / 62);
127 | }
128 | return $res;
129 | }
130 |
131 | /**
132 | * 校验授权
133 | * validate access
134 | * @param $accessKey
135 | * @param $longUrl
136 | * @throws EasyShortUrlException
137 | */
138 | private function validateAccess($accessKey, $longUrl)
139 | {
140 | $parseResult = parse_url($longUrl);
141 | if (!isset($parseResult['host']) || empty($parseResult['host'])) {
142 | throw new EasyShortUrlException('error long url');
143 | }
144 | $res = DB::getInstance()->row("SELECT * FROM esu_access WHERE access_key = ? AND access_domain = ?", $accessKey, $parseResult['host']);
145 | if (empty($res)) {
146 | throw new EasyShortUrlException('not access');
147 | }
148 | }
149 |
150 | /**
151 | * 校验跳转授权
152 | * validate access by code
153 | */
154 | private function validateAccessByCode($code)
155 | {
156 | $res = DB::getInstance()->row("SELECT id,long_url,access_key FROM esu_url WHERE code = ?", $code);
157 | if (empty($res)) {
158 | throw new EasyShortUrlException('not found long url');
159 | }
160 |
161 | $this->validateAccess($res['access_key'], $res['long_url']);
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/Exception/EasyShortUrlException.php:
--------------------------------------------------------------------------------
1 | ';
32 | print_r($data);
33 | echo PHP_EOL;
34 | }
35 | }
36 |
37 | if (!function_exists('pe')) {
38 | /**
39 | * 开发调试
40 | * @param $data
41 | */
42 | function pe($data)
43 | {
44 | p($data);
45 | exit;
46 | }
47 | }
48 |
49 | /**
50 | * 不同环境下获取真实的IP
51 | * @return array|false|mixed|string
52 | */
53 | function esu_get_ip() {
54 | // 判断服务器是否允许$_SERVER
55 | if(isset($_SERVER)){
56 | if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
57 | $realip = $_SERVER['HTTP_X_FORWARDED_FOR'];
58 | }elseif(isset($_SERVER['HTTP_CLIENT_IP'])) {
59 | $realip = $_SERVER['HTTP_CLIENT_IP'];
60 | }else{
61 | $realip = $_SERVER['REMOTE_ADDR'];
62 | }
63 | }else{
64 | // 不允许就使用getenv获取
65 | if(getenv('HTTP_X_FORWARDED_FOR')){
66 | $realip = getenv( "HTTP_X_FORWARDED_FOR");
67 | }elseif(getenv('HTTP_CLIENT_IP')) {
68 | $realip = getenv('HTTP_CLIENT_IP');
69 | }else{
70 | $realip = getenv('REMOTE_ADDR');
71 | }
72 | }
73 | return $realip;
74 | }
75 |
76 | /**
77 | * 获取 session key
78 | * @param bool $refresh
79 | * @return mixed
80 | */
81 | function esu_session_key($refresh = false) {
82 | session_start();
83 | $sid = session_id();
84 |
85 | $lifeTime = env('WEB_SESSION_LIFE'); // 一个 session key 有效期 xx 秒
86 |
87 | if (isset($_SESSION[$sid]) && $_SESSION[$sid]['expire'] > time()) {
88 | if ($refresh) {
89 | // 刷新有效期
90 | $_SESSION[$sid]['expire'] = time() + $lifeTime;
91 | return $_SESSION[$sid]['key'];
92 | } else {
93 | return $_SESSION[$sid]['key'];
94 | }
95 | } else {
96 | $_SESSION[$sid] = [
97 | 'key' => esu_session_key_gen($sid),
98 | 'expire' => time() + $lifeTime,
99 | ];
100 | return $_SESSION[$sid]['key'];
101 | }
102 | }
103 |
104 | /**
105 | * session key 生成
106 | * @param $sid
107 | * @return string
108 | */
109 | function esu_session_key_gen($sid) {
110 | return md5($sid . time() . 'hey!easy-short-url');
111 | }
112 |
113 | /**
114 | * 授权校验
115 | */
116 | function esu_validate_access()
117 | {
118 | $accessPass = false;
119 | if (isset($_POST['access_key']) && in_array($_POST['access_key'], explode('|', env('ACCESS_KEY')))) { // API开发者授权
120 | $accessPass = true;
121 | }
122 | if (isset($_POST['session_key']) && $_POST['session_key'] == esu_session_key()) { // web授权
123 | $accessPass = true;
124 | }
125 | if (!$accessPass) {
126 | header('HTTP/1.1 401 Unauthorized');
127 | exit;
128 | }
129 | }
130 |
131 | function response($data, $code, $msg = '')
132 | {
133 | return [
134 | 'code' => $code,
135 | 'data' => $data,
136 | 'msg' => $msg,
137 | ];
138 | }
139 |
140 | function response_success($data = [])
141 | {
142 | return response($data, '0', 'ok');
143 | }
144 |
145 | function response_error($msg = 'error', $data = [])
146 | {
147 | return response($data, '1', $msg);
148 | }
149 |
150 | function api_success($data)
151 | {
152 | exit(json_encode(response_success($data)));
153 | }
154 |
155 | function api_error($msg = 'error', $data = [])
156 | {
157 | exit(json_encode(response_error($msg, $data)));
158 | }
159 |
160 | function api_response($data, $code, $msg = '')
161 | {
162 | exit(json_encode(response($data, $code, $msg)));
163 | }
--------------------------------------------------------------------------------
/src/Router.php:
--------------------------------------------------------------------------------
1 | uri = $uri;
20 | }
21 |
22 | /**
23 | * 路由分发
24 | * router dispatch
25 | */
26 | public function dispatch()
27 | {
28 | if (method_exists($this, $this->uri)) {
29 | call_user_func([$this, $this->uri]);
30 | } else {
31 | $this->redirectLongUrl();
32 | }
33 | exit;
34 | }
35 |
36 | /**
37 | * web admin
38 | */
39 | public function web_admin()
40 | {
41 | require ESU_ROOT_PATH . '/src/WebAdmin.php';
42 | exit;
43 | }
44 |
45 | /**
46 | * web api
47 | */
48 | public function api_gen()
49 | {
50 | try {
51 | if ($_POST['type'] == 'to_short') {
52 | $longUrl = urldecode($_POST['content']);
53 | if (
54 | empty($_POST['content'])
55 | || (strpos($longUrl, 'http://') !== 0 && strpos($longUrl, 'https://') !== 0)
56 | ) {
57 | throw new EasyShortUrlException('error scheme, please start with http:// or https://');
58 | }
59 | $shortUrl = (EasyShortUrl::getInstance())->toShort($longUrl, $_POST['access_key']);;
60 | api_success($shortUrl);
61 | } elseif ($_POST['type'] == 'to_long') {
62 | $code = trim(parse_url(urldecode($_POST['content']), PHP_URL_PATH), '/');
63 | $longUrl = (EasyShortUrl::getInstance())->toLong($code);;
64 | api_success($longUrl);
65 | } else {
66 | throw new EasyShortUrlException('api not found');
67 | }
68 | } catch (\Exception $e) {
69 | api_error($e->getMessage());
70 | }
71 | }
72 |
73 | /**
74 | * 跳转长网址
75 | * redirect to long url
76 | */
77 | public function redirectLongUrl()
78 | {
79 | try {
80 | if (env('ESU_CACHE_OPEN') === '1') {
81 | $cacheKey = Cache::key('mapping_code_and_long_url', ['code' => $this->uri]);
82 | $cache = Cache::client();
83 | $mapping = $cache->getItem($cacheKey);
84 | if (!$mapping->isHit()) {
85 | // 元素在缓存中不存在,被动缓存
86 | $longUrl = (EasyShortUrl::getInstance())->toLong($this->uri);;
87 | $mapping->set($longUrl);
88 | $cache->save($mapping);
89 | } else {
90 | $longUrl = $mapping->get();
91 | }
92 | }
93 |
94 | // 未启用缓存或从缓存取出失败
95 | if (!isset($longUrl) || empty($longUrl)) {
96 | $longUrl = (EasyShortUrl::getInstance())->toLong($this->uri);;
97 | }
98 |
99 | // 不启用缓存,才做数据统计
100 | if (env('ESU_CACHE_OPEN') !== '1') {
101 | (EasyShortUrl::getInstance())->requestNum($this->uri);;
102 | }
103 |
104 | header('Location:' . $longUrl, true, 302);
105 | exit;
106 | } catch (\Exception $e) {
107 | // todo write log
108 | header("HTTP/1.1 404 Not Found");
109 | exit;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/WebAdmin.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 短网址
5 |
6 |
262 |
263 |
264 |
269 |
270 |
271 |
272 |
273 | -
274 | 缩短网址
275 |
276 | -
277 | 网址还原
278 |
279 |
280 |
281 | -
282 | GitHub
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
332 |
333 |
334 |
335 |
367 |
368 |
369 |
--------------------------------------------------------------------------------
/static/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenlongqiang/easy-short-url/5a265ef9f6b96f878c932a5366dccfc60c83bb98/static/img.png
--------------------------------------------------------------------------------