界面截图
不想自己搭建也可以使用:https://www.judy.xx.kg/m3u8.php
更多内容请看主页 https://www.judy.xx.kg
<?php
$allowed_ext = ['m3u', 'txt'];
$upload_dir = __DIR__ . '/uploads/';
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
// 网站上线时间(请按实际上线时间修改)
define('SITE_LAUNCH_TIME', '2025-07-27 08:00:00');
// 记录上传者IP及文件名字,格式为 IP-----文件名字,覆盖写入
function log_upload_ip($ip, $orig_name) {
$ip_dir = __DIR__ . '/ip/';
if (!is_dir($ip_dir)) mkdir($ip_dir, 0777, true);
$ipfile = $ip_dir . $ip;
file_put_contents($ipfile, $ip . '-----' . $orig_name, LOCK_EX);
}
// 统计信息
$all_files = array_diff(scandir($upload_dir), ['.', '..']);
$total_files = count($all_files);
$total_size = 0;
foreach ($all_files as $f) $total_size += filesize($upload_dir . $f);
// 返回 JSON 请求(AJAX 上传)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file']) && isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
$file = $_FILES['file'];
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_ext)) {
http_response_code(400);
echo json_encode(['error' => '只允许 .m3u 或 .txt 文件']);
exit;
}
$filename = uniqid('upload_', true) . '.' . $ext;
$dest = $upload_dir . $filename;
if (move_uploaded_file($file['tmp_name'], $dest)) {
log_upload_ip($_SERVER['REMOTE_ADDR'], $file['name']);
echo json_encode(['success' => true, 'link' => get_file_url($filename)]);
exit;
} else {
http_response_code(500);
echo json_encode(['error' => '文件上传失败']);
exit;
}
}
// 普通远程下载
$msg = '';
$link = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['remote_url'])) {
$remote_url = trim($_POST['remote_url']);
$basename = basename(parse_url($remote_url, PHP_URL_PATH));
$ext = strtolower(pathinfo($basename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_ext)) {
$msg = "只允许下载 .m3u 或 .txt 文件";
} else {
$newname = uniqid('remote_', true) . '.' . $ext;
$dest = $upload_dir . $newname;
$filedata = @file_get_contents($remote_url, false, stream_context_create(['http'=>['timeout'=>15]]), 0, 10*1024*1024);
if ($filedata !== false) {
file_put_contents($dest, $filedata);
log_upload_ip($_SERVER['REMOTE_ADDR'], $basename);
$msg = "远程下载成功!";
$link = get_file_url($newname);
} else {
$msg = "远程下载失败,无法获取文件。";
}
}
}
function get_file_url($filename) {
$url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http")
. "://$_SERVER[HTTP_HOST]"
. dirname($_SERVER['PHP_SELF']);
$url = rtrim($url, '/\\');
return $url . '/uploads/' . rawurlencode($filename);
}
function size_format($size) {
if ($size >= 1073741824) return round($size / 1073741824, 2) . ' GB';
if ($size >= 1048576) return round($size / 1048576, 2) . ' MB';
if ($size >= 1024) return round($size / 1024, 2) . ' KB';
return $size . ' B';
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>文件上传 | M3U / TXT 托管</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
--c-bg: linear-gradient(135deg, #dbeafe, #eff6ff, #ffffff);
--c-card: #fff;
--c-main: #2a7bf6;
--c-shadow: 0 8px 32px rgba(42,123,246,0.08);
--c-border: #e9f0fb;
--c-success: #28c07d;
--c-error: #eb4c4c;
--c-muted: #bfcfe7;
--c-btn: #eef5ff;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
background: var(--c-bg);
font-family: 'Inter', sans-serif;
}
.container {
background: var(--c-card);
border-radius: 2.2em;
box-shadow: var(--c-shadow);
max-width: 480px;
margin: 6vh auto;
padding: 2.5em 2em;
}
h2 {
text-align: center;
color: var(--c-main);
}
.dropzone {
border: 2px dashed var(--c-main);
background: #f0f8ff;
padding: 2em;
border-radius: 1.5em;
text-align: center;
cursor: pointer;
transition: background 0.3s;
}
.dropzone.dragover {
background: #e0f0ff;
}
.dropzone input {
display: none;
}
.dropzone-text {
font-size: 1em;
color: #2a7bf6;
}
form {
margin-top: 1em;
display: flex;
gap: .6em;
}
input[type="url"] {
flex: 1;
padding: .6em .9em;
border: 1px solid var(--c-border);
border-radius: 1.2em;
}
button {
padding: .6em 1.4em;
border: none;
background: var(--c-main);
color: white;
border-radius: 1.2em;
cursor: pointer;
}
.progress-container {
margin-top: 1em;
width: 100%;
background-color: #eef3fc;
border-radius: 1.2em;
height: 1.2em;
position: relative;
overflow: hidden;
display: none;
}
.progress-bar {
height: 100%;
background-color: var(--c-main);
width: 0%;
transition: width 0.3s ease;
}
.progress-text {
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
font-size: .86em;
color: #333;
line-height: 1.2em;
}
.msg {
margin-top: 1.2em;
padding: 0.8em;
text-align: center;
border-radius: 1.2em;
background: #f9fbff;
border: 1px solid var(--c-border);
}
.msg.success {
color: var(--c-success);
background: #eafcf6;
}
.msg.error {
color: var(--c-error);
background: #fff5f6;
}
.upload-link {
margin-top: 1.2em;
word-break: break-all;
background: #f5faff;
border-radius: 1.2em;
padding: .6em .9em;
border: 1px solid var(--c-border);
font-size: .95em;
color: #257af8;
}
.stats {
text-align: center;
margin-top: 2.2em;
font-size: .92em;
color: #666;
}
/* 运行时间流光效果 */
.runtime-bar {
margin-top: 3em;
text-align: center;
font-size: 0.95em;
padding: 1em;
background: linear-gradient(90deg, #2a7bf6, #9cbff8, #2a7bf6);
background-size: 200% auto;
color: white;
animation: shimmer 3s linear infinite;
border-radius: 1.2em;
box-shadow: 0 0 12px rgba(0, 140, 255, 0.3);
}
@keyframes shimmer {
0% { background-position: 0% 50%; }
100% { background-position: 200% 50%; }
}
</style>
</head>
<body>
<div class="container">
<h2>IPTV-M3U / TXT 上传托管</h2>
<div class="dropzone" id="dropzone">
<span class="dropzone-text">点击或拖拽 .m3u/.txt 文件至此上传</span>
<form id="uploadForm"><input type="file" id="fileInput" name="file" accept=".m3u,.txt"></form>
</div>
<div class="progress-container" id="progressBox">
<div class="progress-bar" id="progressBar"></div>
<div class="progress-text" id="progressText">0%</div>
</div>
<div class="msg" id="uploadMsg" style="display:none;"></div>
<div class="upload-link" id="uploadLink" style="display:none;"></div>
<form method="post" style="margin-top: 1.5em;">
<input type="url" name="remote_url" placeholder="粘贴远程 .m3u/.txt 地址" pattern="https?://.+" required>
<button type="submit">远程下载</button>
</form>
</div>
<div class="stats">
当前已托管 <strong><?php echo $total_files;?></strong> 个文件,合计 <strong><?php echo size_format($total_size);?></strong>
</div>
<!-- 网站累计运行时长 流光效果 -->
<div class="runtime-bar" id="runtimeBar">
网站已累计运行 <span id="runtime">加载中…</span>
</div>
<?php if ($msg): ?>
<script>
window.addEventListener('DOMContentLoaded', function() {
const m = document.getElementById("uploadMsg");
m.innerText = <?php echo json_encode($msg); ?>;
m.classList.add(<?php echo strpos($msg, "成功") !== false ? "'success'" : "'error'"; ?>);
m.style.display = "block";
<?php if ($link): ?>
const l = document.getElementById("uploadLink");
l.innerText = <?php echo json_encode($link); ?>;
l.style.display = "block";
<?php endif; ?>
});
</script>
<?php endif; ?>
<script>
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('fileInput');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const progressBox = document.getElementById('progressBox');
const uploadMsg = document.getElementById('uploadMsg');
const uploadLink = document.getElementById('uploadLink');
dropzone.addEventListener('click', () => fileInput.click());
dropzone.addEventListener('dragover', (e) => {
e.preventDefault();
dropzone.classList.add('dragover');
});
dropzone.addEventListener('dragleave', () => dropzone.classList.remove('dragover'));
dropzone.addEventListener('drop', (e) => {
e.preventDefault();
dropzone.classList.remove('dragover');
const files = e.dataTransfer.files;
if (files.length) {
uploadFile(files[0]);
}
});
fileInput.addEventListener('change', () => {
if (fileInput.files.length) uploadFile(fileInput.files[0]);
});
function uploadFile(file) {
const ext = file.name.split('.').pop().toLowerCase();
if (!['m3u', 'txt'].includes(ext)) {
alert('只允许上传 .m3u 或 .txt 文件');
return;
}
const formData = new FormData();
formData.append('file', file);
const xhr = new XMLHttpRequest();
xhr.open('POST', '', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
progressBar.style.width = percent + '%';
progressText.textContent = percent + '%';
}
});
xhr.onloadstart = () => {
progressBox.style.display = 'block';
uploadMsg.style.display = 'none';
uploadLink.style.display = 'none';
progressBar.style.width = '0%';
progressText.textContent = '0%';
};
xhr.onload = () => {
if (xhr.status === 200) {
const res = JSON.parse(xhr.responseText);
if (res.success) {
uploadMsg.textContent = '上传成功!';
uploadMsg.className = 'msg success';
uploadMsg.style.display = 'block';
uploadLink.textContent = res.link;
uploadLink.style.display = 'block';
}
} else {
uploadMsg.textContent = '上传失败';
uploadMsg.className = 'msg error';
uploadMsg.style.display = 'block';
}
};
xhr.onerror = () => {
uploadMsg.textContent = '网络错误,上传失败';
uploadMsg.className = 'msg error';
uploadMsg.style.display = 'block';
};
xhr.send(formData);
}
// 网站累计运行时间(年月日时分秒)
(function(){
var launchTime = <?php echo strtotime(SITE_LAUNCH_TIME); ?> * 1000;
function formatTime(diff){
var seconds = Math.floor(diff / 1000);
var years = Math.floor(seconds / (365*24*3600));
seconds = seconds % (365*24*3600);
var months = Math.floor(seconds / (30*24*3600));
seconds = seconds % (30*24*3600);
var days = Math.floor(seconds / (24*3600));
seconds = seconds % (24*3600);
var hours = Math.floor(seconds / 3600);
seconds = seconds % 3600;
var minutes = Math.floor(seconds / 60);
seconds = seconds % 60;
var parts = [];
if(years) parts.push(years+"年");
if(months) parts.push(months+"月");
if(days) parts.push(days+"天");
parts.push(hours+"时"+minutes+"分"+seconds+"秒");
return parts.join('');
}
function updateRuntime(){
var now = Date.now();
var diff = now - launchTime;
document.getElementById('runtime').textContent = formatTime(diff);
setTimeout(updateRuntime, 1000);
}
updateRuntime();
})();
</script>
</body>
</html>