آموزش ساخت یک سرور با پایتون (سرور فایل)

خب شما یک پوشه میسازید با نام : File server

در این پوشه یک پوشه با نام : server

بعد داخل پوشه server یک فایل پایتونی میسازید .

موارد لازم :

1- پایتون

2- کتابخانه flask

داخل فایل پایتونی با اسم app کد زیر را وارد میکنید

import os
import sqlite3
import secrets
from datetime import datetime, timedelta
from flask import Flask, request, render_template, send_file, redirect, url_for, flash
from werkzeug.utils import secure_filename

app = Flask(__name__)
app.secret_key = "change-this-secret-key"

UPLOAD_FOLDER = "uploads"
DATABASE = "files.db"
MAX_CONTENT_LENGTH = 1024 * 1024 * 1024  # 1 GB

app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
app.config["MAX_CONTENT_LENGTH"] = MAX_CONTENT_LENGTH

os.makedirs(UPLOAD_FOLDER, exist_ok=True)


def get_db():
    conn = sqlite3.connect(DATABASE)
    conn.row_factory = sqlite3.Row
    return conn


def init_db():
    conn = get_db()
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS files (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            code TEXT UNIQUE NOT NULL,
            original_name TEXT NOT NULL,
            stored_path TEXT NOT NULL,
            uploaded_at TEXT NOT NULL,
            expires_at TEXT NOT NULL,
            max_downloads INTEGER NOT NULL,
            download_count INTEGER NOT NULL DEFAULT 0
        )
    """)
    conn.commit()
    conn.close()


def generate_code(length=8):
    alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
    return "".join(secrets.choice(alphabet) for _ in range(length))


def unique_code():
    conn = get_db()
    cursor = conn.cursor()

    while True:
        code = generate_code()
        cursor.execute("SELECT id FROM files WHERE code = ?", (code,))
        row = cursor.fetchone()
        if not row:
            conn.close()
            return code


def delete_file_record(file_row):
    try:
        if os.path.exists(file_row["stored_path"]):
            os.remove(file_row["stored_path"])
    except Exception:
        pass

    conn = get_db()
    cursor = conn.cursor()
    cursor.execute("DELETE FROM files WHERE id = ?", (file_row["id"],))
    conn.commit()
    conn.close()


@app.route("/")
def home():
    return render_template("home.html")


@app.route("/upload-page")
def upload_page():
    return render_template("upload.html")


@app.route("/download-page")
def download_page():
    return render_template("download.html")


@app.route("/upload", methods=["POST"])
def upload_file():
    if "file" not in request.files:
        flash("فایلی ارسال نشده است.")
        return redirect(url_for("upload_page"))

    file = request.files["file"]
    if file.filename == "":
        flash("هیچ فایلی انتخاب نشده است.")
        return redirect(url_for("upload_page"))

    filename = secure_filename(file.filename)
    if not filename:
        flash("نام فایل معتبر نیست.")
        return redirect(url_for("upload_page"))

    try:
        expire_value = int(request.form.get("expire_value", "1"))
        expire_unit = request.form.get("expire_unit", "hours")
        max_downloads = int(request.form.get("max_downloads", "1"))
    except ValueError:
        flash("مقادیر وارد شده معتبر نیستند.")
        return redirect(url_for("upload_page"))

    if expire_value < 1:
        flash("مدت اعتبار باید حداقل 1 باشد.")
        return redirect(url_for("upload_page"))

    if max_downloads < 1:
        flash("تعداد دانلود باید حداقل 1 باشد.")
        return redirect(url_for("upload_page"))

    now = datetime.utcnow()

    if expire_unit == "minutes":
        expires_at = now + timedelta(minutes=expire_value)
    elif expire_unit == "hours":
        expires_at = now + timedelta(hours=expire_value)
    elif expire_unit == "days":
        expires_at = now + timedelta(days=expire_value)
    else:
        flash("واحد زمان نامعتبر است.")
        return redirect(url_for("upload_page"))

    code = unique_code()
    stored_filename = f"{code}_{filename}"
    stored_path = os.path.join(app.config["UPLOAD_FOLDER"], stored_filename)
    file.save(stored_path)

    conn = get_db()
    cursor = conn.cursor()
    cursor.execute("""
        INSERT INTO files (
            code, original_name, stored_path,
            uploaded_at, expires_at, max_downloads, download_count
        )
        VALUES (?, ?, ?, ?, ?, ?, 0)
    """, (
        code,
        filename,
        stored_path,
        now.isoformat(),
        expires_at.isoformat(),
        max_downloads
    ))
    conn.commit()
    conn.close()

    return render_template(
        "success.html",
        code=code,
        expires_at=expires_at.strftime("%Y-%m-%d %H:%M:%S UTC"),
        max_downloads=max_downloads
    )


@app.route("/download", methods=["POST"])
def download_file():
    code = request.form.get("code", "").strip().upper()

    if not code:
        flash("کد را وارد کنید.")
        return redirect(url_for("download_page"))

    conn = get_db()
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM files WHERE code = ?", (code,))
    file_row = cursor.fetchone()

    if not file_row:
        conn.close()
        flash("کد نامعتبر است یا فایل پیدا نشد.")
        return redirect(url_for("download_page"))

    now = datetime.utcnow()
    expires_at = datetime.fromisoformat(file_row["expires_at"])

    # اگر فایل منقضی شده باشد
    if now > expires_at:
        conn.close()
        delete_file_record(file_row)
        flash("اعتبار فایل به پایان رسیده و فایل حذف شد.")
        return redirect(url_for("download_page"))

    # اگر تعداد دانلود پر شده باشد
    if file_row["download_count"] >= file_row["max_downloads"]:
        conn.close()
        delete_file_record(file_row)
        flash("حداکثر تعداد دانلود این فایل تمام شده و فایل حذف شد.")
        return redirect(url_for("download_page"))

    if not os.path.exists(file_row["stored_path"]):
        conn.close()
        flash("فایل روی سرور موجود نیست.")
        return redirect(url_for("download_page"))

    new_count = file_row["download_count"] + 1

    cursor.execute(
        "UPDATE files SET download_count = ? WHERE id = ?",
        (new_count, file_row["id"])
    )
    conn.commit()
    conn.close()

    # اگر این آخرین دانلود مجاز بود، بعد از این دانلود حذف شود
    response = send_file(
        file_row["stored_path"],
        as_attachment=True,
        download_name=file_row["original_name"]
    )

    if new_count >= file_row["max_downloads"]:
        try:
            if os.path.exists(file_row["stored_path"]):
                os.remove(file_row["stored_path"])
        except Exception:
            pass

        conn = get_db()
        cursor = conn.cursor()
        cursor.execute("DELETE FROM files WHERE id = ?", (file_row["id"],))
        conn.commit()
        conn.close()

    return response


if __name__ == "__main__":
    init_db()
    app.run(host="0.0.0.0", port=5000, debug=True)

خب حالا داخل پوشه server یک پوشه با اسم : templates میسازید .

داخل اون پوشه

1- یک فایل میسازید با اسم و پسوند : download.html

کد داخل آن :

<!DOCTYPE html>
<html lang="fa">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>دانلود فایل</title>
    <style>
        body {
            margin: 0;
            font-family: Tahoma, Arial, sans-serif;
            background: #f4f6f9;
        }
        .container {
            max-width: 650px;
            margin: 50px auto;
            background: white;
            padding: 30px;
            border-radius: 18px;
            box-shadow: 0 6px 22px rgba(0,0,0,0.1);
        }
        h1 {
            text-align: center;
            color: #222;
        }
        label {
            display: block;
            margin-top: 18px;
            margin-bottom: 8px;
            font-weight: bold;
        }
        input[type="text"] {
            width: 100%;
            padding: 12px;
            border: 1px solid #bbb;
            border-radius: 10px;
            box-sizing: border-box;
        }
        button {
            margin-top: 25px;
            width: 100%;
            padding: 14px;
            border: none;
            border-radius: 12px;
            background: #28a745;
            color: white;
            font-size: 16px;
            cursor: pointer;
        }
        button:hover {
            background: #1f7d34;
        }
        .back {
            display: inline-block;
            margin-top: 18px;
            text-decoration: none;
            color: #007bff;
        }
        .flash {
            background: #ffe3e3;
            color: #a40000;
            padding: 12px;
            border-radius: 10px;
            margin-bottom: 15px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>دانلود فایل</h1>

        {% with messages = get_flashed_messages() %}
          {% if messages %}
            {% for message in messages %}
              <div class="flash">{{ message }}</div>
            {% endfor %}
          {% endif %}
        {% endwith %}

        <form action="/download" method="post">
            <label>کد فایل را وارد کنید</label>
            <input type="text" name="code" placeholder="مثلاً ABCD1234" required>
            <button type="submit">دانلود فایل</button>
        </form>

        <a class="back" href="/">بازگشت به صفحه اصلی</a>
    </div>
</body>
</html>

2- یک فایل با نام و پسوند : home.html

داخل آن کد :

<!DOCTYPE html>
<html lang="fa">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>سرور آپلود فایل</title>
    <style>
        body {
            margin: 0;
            font-family: Tahoma, Arial, sans-serif;
            background: linear-gradient(135deg, #e3f2fd, #f8f9fa);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }
        .box {
            background: white;
            width: 420px;
            padding: 35px;
            border-radius: 18px;
            box-shadow: 0 8px 30px rgba(0,0,0,0.12);
            text-align: center;
        }
        h1 {
            margin-bottom: 25px;
            color: #222;
        }
        .btn {
            display: block;
            width: 100%;
            margin: 15px 0;
            padding: 14px;
            text-decoration: none;
            color: white;
            background: #007bff;
            border-radius: 12px;
            font-size: 17px;
            transition: 0.2s;
        }
        .btn:hover {
            background: #0056b3;
        }
        .btn.secondary {
            background: #28a745;
        }
        .btn.secondary:hover {
            background: #1f7d34;
        }
    </style>
</head>
<body>
    <div class="box">
        <h1>سرور آپلود فایل</h1>
        <a class="btn" href="/upload-page">ورود به صفحه آپلود</a>
        <a class="btn secondary" href="/download-page">ورود به صفحه دانلود</a>
    </div>
</body>
</html>

3- یک فایل دیگر با نام و پسوند : success.html

داخل آن کد زیر را وارد میکنید :

<!DOCTYPE html>
<html lang="fa">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>آپلود موفق</title>
    <style>
        body {
            margin: 0;
            font-family: Tahoma, Arial, sans-serif;
            background: #eef7ee;
        }
        .container {
            max-width: 650px;
            margin: 50px auto;
            background: white;
            padding: 30px;
            border-radius: 18px;
            box-shadow: 0 6px 22px rgba(0,0,0,0.1);
            text-align: center;
        }
        h1 {
            color: #1f7d34;
        }
        .code-box {
            background: #f1f8ff;
            border: 2px dashed #007bff;
            padding: 20px;
            margin: 20px 0;
            border-radius: 14px;
            font-size: 28px;
            font-weight: bold;
            letter-spacing: 3px;
            color: #007bff;
        }
        .info {
            margin-top: 10px;
            color: #333;
            line-height: 1.9;
        }
        .btn {
            display: inline-block;
            margin-top: 20px;
            padding: 12px 20px;
            text-decoration: none;
            color: white;
            background: #007bff;
            border-radius: 12px;
        }
        .btn:hover {
            background: #0056b3;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>آپلود با موفقیت انجام شد</h1>
        <p>کد مخصوص فایل شما:</p>
        <div class="code-box">{{ code }}</div>

        <div class="info">
            <p>تاریخ انقضا: {{ expires_at }}</p>
            <p>حداکثر تعداد دانلود: {{ max_downloads }}</p>
        </div>

        <a class="btn" href="/">بازگشت به صفحه اصلی</a>
    </div>
</body>
</html>

4- داخل همان پوشه یک فایل با اسم و پسوند : upload.html

کد زیر را داخل فایل وارد میکنید :

<!DOCTYPE html>
<html lang="fa">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>آپلود فایل</title>
    <style>
        body {
            margin: 0;
            font-family: Tahoma, Arial, sans-serif;
            background: #f4f6f9;
        }
        .container {
            max-width: 650px;
            margin: 50px auto;
            background: white;
            padding: 30px;
            border-radius: 18px;
            box-shadow: 0 6px 22px rgba(0,0,0,0.1);
        }
        h1 {
            text-align: center;
            color: #222;
        }
        label {
            display: block;
            margin-top: 18px;
            margin-bottom: 8px;
            font-weight: bold;
        }
        input[type="file"],
        input[type="number"],
        select {
            width: 100%;
            padding: 12px;
            border: 1px solid #bbb;
            border-radius: 10px;
            box-sizing: border-box;
        }
        button {
            margin-top: 25px;
            width: 100%;
            padding: 14px;
            border: none;
            border-radius: 12px;
            background: #007bff;
            color: white;
            font-size: 16px;
            cursor: pointer;
        }
        button:hover {
            background: #0056b3;
        }
        .back {
            display: inline-block;
            margin-top: 18px;
            text-decoration: none;
            color: #007bff;
        }
        .flash {
            background: #ffe3e3;
            color: #a40000;
            padding: 12px;
            border-radius: 10px;
            margin-bottom: 15px;
        }
        .row {
            display: flex;
            gap: 12px;
        }
        .row > div {
            flex: 1;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>آپلود فایل</h1>

        {% with messages = get_flashed_messages() %}
          {% if messages %}
            {% for message in messages %}
              <div class="flash">{{ message }}</div>
            {% endfor %}
          {% endif %}
        {% endwith %}

        <form action="/upload" method="post" enctype="multipart/form-data">
            <label>انتخاب فایل</label>
            <input type="file" name="file" required>

            <label>مدت اعتبار فایل</label>
            <div class="row">
                <div>
                    <input type="number" name="expire_value" min="1" value="1" required>
                </div>
                <div>
                    <select name="expire_unit" required>
                        <option value="minutes">دقیقه</option>
                        <option value="hours" selected>ساعت</option>
                        <option value="days">روز</option>
                    </select>
                </div>
            </div>

            <label>حذف فایل بعد از چند بار دانلود</label>
            <input type="number" name="max_downloads" min="1" value="1" required>

            <button type="submit">تأیید و آپلود</button>
        </form>

        <a class="back" href="/">بازگشت به صفحه اصلی</a>
    </div>
</body>
</html>

حالا از قسمت بالای پوشه server کلمه cmd جای آدرس مینویسیم و وارد cmd میشیم .

حالا کد :

python app.py

را ارسال کنید و سرور روشن شد .

حالا اگر به داخل گوگل بروید و آدرس :

http://127.0.0.1:5000

وارد سرور میشوید .

برای خاموش کردن صفحه داخل همون cmd باز ، کنترل سی را بگیرید.

ساختار کلی پروژه :

file_server/

├── app.py

├── files.db

├── uploads/

└── templates/

├── home.html

├── upload.html

├── download.html

└── success.html

کل پروژه را از لینک زیر دانلود کنید :

https://my.files.ir/drive/s/5oFQElodY5mDvQwLfB84fVy30e6Q9Z:MTQ4MjQxMnxwYQ

رمز : artinkarimian

کانال روبیکا من : https://rubika.ir/artinkarimian3