-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2d8dab7
Showing
5 changed files
with
341 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
data.db |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
## 短链接生成 | ||
|
||
又一个基于 PHP 简单实现的短链接在线生成工具,简单配置,快速搭建。 | ||
|
||
## 快速配置 | ||
|
||
### 安装 | ||
#### 1. 下载源码,部署至服务器,环境 `PHP > 5.6`,需安装 `PDO` 扩展。 | ||
#### 2. 配置 Nginx,参考如下: | ||
```conf | ||
server { | ||
listen 80; | ||
server_name url.local; | ||
root /www/url; | ||
index index.php index.html index.htm; | ||
access_log /dev/null; | ||
error_log /var/log/nginx/nginx.url.error.log warn; | ||
# 伪静态 必须 | ||
location / { | ||
try_files $uri $uri/ /index.php?$query_string; | ||
} | ||
# sqlite 数据库文件禁止访问 必须 | ||
location ~ /(data\.db) { | ||
deny all; | ||
} | ||
location ~ \.php$ { | ||
fastcgi_pass unix:/dev/shm/php-cgi.sock; | ||
include fastcgi-php.conf; | ||
include fastcgi_params; | ||
} | ||
} | ||
``` | ||
#### 3. 配置数据库,支持 MySQL 和 SQLite。 | ||
|
||
##### 3.1 MySQL 配置 | ||
|
||
###### 3.1.1 编辑 index.php | ||
|
||
``` | ||
<?php | ||
// 数据库连接字符串 host 主机名; dbname 数据库名; charset 字符集编码 | ||
define('DB_DSN', 'mysql:host=mysql5;dbname=short;charset=utf8mb4'); | ||
// 数据库用户名 | ||
define('DB_USER', 'root'); | ||
// 数据库密码 | ||
define('DB_PASSWD', '123456'); | ||
``` | ||
|
||
###### 3.1.2 导入数据库表结构 | ||
使用工具(Navicat、PHPMyAdmin等)连接 MySQL 服务,创建数据库 `short`,并导入 `mysql.db.sql` | ||
|
||
##### 3.2 SQLite 配置: | ||
|
||
###### 3.2.1 编辑 index.php | ||
|
||
``` | ||
<?php | ||
// 数据库连接字符串 host 主机名; dbname 数据库名; charset 字符集编码 | ||
define('DB_DSN', 'sqlite:data.db'); | ||
// 数据库用户名 | ||
define('DB_USER', null); | ||
// 数据库密码 | ||
define('DB_PASSWD', null); | ||
``` | ||
|
||
###### 3.2.2 创建数据库文件 | ||
复制 `sqlite.db.exp` 为 `data.db` | ||
|
||
### 4 配置短链接字符长度 | ||
|
||
```php | ||
// 生成短链接随机字符长度 默认 6 位 不超过 32 位 | ||
define('CODE_LENGTH', 6); | ||
``` | ||
|
||
## TODO List | ||
- 后台管理 | ||
- 域名黑名单 | ||
- 密码访问 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
<?php | ||
|
||
// 数据库连接字符串 | ||
// MySQL示例 mysql:host=localhost;dbname=testdb;charset=utf8mb4 | ||
define('DB_DSN', 'sqlite:data.db'); | ||
|
||
// 数据库用户名 | ||
define('DB_USER', null); | ||
|
||
// 数据库密码 | ||
define('DB_PASSWD', null); | ||
|
||
// 生成短链接随机字符长度 默认 6 位 不超过 32 位 | ||
define('CODE_LENGTH', 6); | ||
|
||
if ($_SERVER['REQUEST_METHOD'] == 'POST') { | ||
|
||
if (empty($_POST['url'])) { | ||
json(-2, '网址不能为空!'); | ||
} | ||
|
||
$url = $_POST['url']; | ||
|
||
if (!filter_var($url, FILTER_VALIDATE_URL)) { | ||
json(-3, '网址格式不正确!'); | ||
} | ||
|
||
$db = db(); | ||
$hash = md5($url); | ||
|
||
$stmt = $db->prepare("select * from url where hash = ?"); | ||
$stmt->execute([$hash]); | ||
$data = $stmt->fetchAll(); | ||
|
||
if ($data) { | ||
$code = current($data)['code']; | ||
} else { | ||
$code = generate_code(); | ||
|
||
$stmt = $db->prepare("select * from url where code = ?"); | ||
$stmt->execute([$code]); | ||
$exist = $stmt->fetchColumn(); | ||
if ($exist) { | ||
json(-4, '天选之子,再来一次!'); | ||
} | ||
|
||
$stmt = $db->prepare("insert into url(code, hash, url) values (?, ?, ?)"); | ||
$result = $stmt->execute([$code, $hash, $url]); | ||
if (!$result) { | ||
json(-5, '系统繁忙,请稍后再试!'); | ||
} | ||
} | ||
|
||
$base_url = $_SERVER['HTTP_HOST'] .'/'. $code; | ||
json(0, 'OK',[ | ||
'short' => $base_url, | ||
'generic' => 'http://' . $base_url, | ||
'long' => 'https://' . $base_url, | ||
]); | ||
} else if ($_SERVER['REQUEST_METHOD'] == 'GET') { | ||
header("Content-Type: text/html"); | ||
if ($_SERVER['REQUEST_URI'] != '/') { | ||
$code = substr($_SERVER['REQUEST_URI'], 1); | ||
$db = db(); | ||
$stmt = $db->prepare("select * from url where code = ?"); | ||
$stmt->execute([$code]); | ||
$data = $stmt->fetchAll(); | ||
if ($data) { | ||
$url = current($data)['url']; | ||
header("Location: {$url}"); | ||
} else { | ||
header("Location: /"); | ||
} | ||
exit(0); | ||
} | ||
} | ||
|
||
function json($code, $msg, $data=[]) { | ||
header("Content-Type: application/json; charset=utf-8"); | ||
echo json_encode(['code' => $code, 'msg' => $msg, 'data' => $data]); | ||
exit(0); | ||
} | ||
|
||
function db() { | ||
try { | ||
$pdo = new PDO(DB_DSN, DB_USER, DB_PASSWD); | ||
} catch (PDOException $e) { | ||
json(-1, '数据库连接失败!'.$e->getMessage()); | ||
} | ||
|
||
return $pdo; | ||
} | ||
|
||
function generate_code() { | ||
$seeds = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 9)); | ||
$depository = []; | ||
for ($i = 0; $i < CODE_LENGTH-1; $i++) { | ||
$depository = array_merge($depository, $seeds); | ||
} | ||
shuffle($depository); | ||
return join('', array_slice($depository, 0, CODE_LENGTH)); | ||
} | ||
|
||
header("Content-Type: text/html"); | ||
|
||
?> | ||
|
||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>短链接生成</title> | ||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script> | ||
<style> | ||
* { | ||
padding: 0; | ||
margin: 0; | ||
box-sizing: border-box; | ||
} | ||
body { | ||
display:flex; | ||
justify-content:center; | ||
align-items: center; | ||
height: 100vh; | ||
color: #333 | ||
} | ||
a { | ||
font-size: .8em; | ||
width: auto; | ||
color: #999; | ||
} | ||
.site-header { | ||
margin-bottom: 14px; | ||
margin-top: -140px; | ||
text-align: center; | ||
} | ||
.main-title { | ||
font-size: 1.8em; | ||
} | ||
.subtitle { | ||
font-size: 1em; | ||
color: #bbb; | ||
font-weight: 400; | ||
margin: 4px 0 10px 0; | ||
} | ||
.site-body { | ||
margin: 24px 0 24px; | ||
} | ||
.site-body-item { | ||
margin: 22px 0 22px 0; | ||
} | ||
.site-input { | ||
border-radius: 3px; | ||
padding: 5px; | ||
font-size: 14px; | ||
border: 1px solid #ccc; | ||
width: 280px; | ||
box-sizing: border-box; | ||
} | ||
.site-button { | ||
background-color: #fff; | ||
color: #333; | ||
text-shadow: 0 1px 0 #fff; | ||
text-decoration: none; | ||
font-weight: 700; | ||
padding: 4px 15px 3px; | ||
border: 1px solid rgba(80,80,90,.2); | ||
border-radius: 3px; | ||
font-size: 14px; | ||
font-family: Arial,sans-serif; | ||
display: inline-block; | ||
line-height: 1.4; | ||
outline: 0; | ||
} | ||
.site-button:hover { | ||
background-color: #f9f9f9; | ||
border: 1px solid rgba(60,60,70,.3); | ||
color: #333; | ||
text-shadow: 0 1px 0 #fff; | ||
text-decoration: none; | ||
font-weight: 700; | ||
cursor: pointer; | ||
} | ||
.site-footer { | ||
text-align: center; | ||
font-size: 12px; | ||
color: #bbb; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div class="container"> | ||
<div class="site-header"> | ||
<h1 class="main-title">短链接生成</h1> | ||
<h2 class="subtitle">人生很短,链接也别太长。</h2> | ||
</div> | ||
<div class="site-body"> | ||
<div class="site-body-item"> | ||
<input type="text" name="url" class="site-input"/> | ||
<input type="button" name="submit" value="Short" class="site-button"/> | ||
</div> | ||
<div class="site-body-item"> | ||
<input type="text" name="short_url" class="site-input" /> | ||
<input type="button" name="copy" value="Copy" class="site-button"/> | ||
</div> | ||
</div> | ||
<div class="site-footer"> | ||
<p><a href="https://blog.wangmao.me">WangMao's Blog</a> | <a href="https://github.com/isecret/short">Github</a></p> | ||
</div> | ||
</div> | ||
<script> | ||
$('input[name=submit]').click(function () { | ||
var url = $('input[name=url]').val(); | ||
|
||
if (url == '') { | ||
alert("链接不能为空!"); | ||
return; | ||
} | ||
|
||
if (!/^http(s)?:\/\//.test(url)) { | ||
alert("链接格式不正确!"); | ||
return; | ||
} | ||
|
||
$.post("/", {url: url}, function (data) { | ||
if (data.code == 0) { | ||
$('input[name=short_url]').val(data.data.generic); | ||
} else { | ||
alert(data.msg); | ||
} | ||
}, 'json') | ||
}); | ||
|
||
$('input[name=copy]').click(function () { | ||
$("input[name=short_url]").focus(); | ||
$("input[name=short_url]").select(); | ||
document.execCommand("Copy"); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
CREATE TABLE `url` ( | ||
`id` int(11) NOT NULL AUTO_INCREMENT, | ||
`code` varchar(32) NOT NULL, | ||
`url` text NOT NULL, | ||
`hash` varchar(32) NOT NULL, | ||
`create_date` datetime DEFAULT CURRENT_TIMESTAMP, | ||
PRIMARY KEY (`id`), | ||
KEY `idx_code` (`code`), | ||
KEY `idx_hash` (`hash`) | ||
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 |
Binary file not shown.