رفع الملفات في PHP مع MySQL

يعد رفع الملفات ميزة شائعة في تطبيقات الويب. قد يحتاج المستخدمون إلى رفع صور الملف الشخصي أو السير الذاتية أو مستندات PDF أو صور المنتج أو المرفقات أو الشهادات أو صور المعرض. يمكن لـ PHP تلقي الملفات المرفوعة والتحقق من صحتها ونقلها إلى مجلد آمن وتخزين معلوماتها في قاعدة بيانات MySQL.

عندما يتم دمج رفع الملفات مع MySQL، عادةً ما يتم تخزين الملف المرفوع نفسه في مجلد على الخادم، بينما تقوم قاعدة البيانات بتخزين معلومات مثل اسم الملف ومسار الملف ونوع الملف وحجم الملف وتاريخ التحميل.

تشرح هذه المقالة رفع الملفات في PHP باستخدام MySQL بالتفصيل، بما في ذلك نماذج رفع HTML، ومعالجة الرفع في PHP، والتحقق من الصحة، والتحقق من نوع الملف، والتحقق من حجم الملف، وأسماء الملفات الآمنة، وتخزين مسارات الملفات في MySQL، وعرض الملفات المرفوعة، وتحديث الملفات المرفوعة، وحذف الملفات المرفوعة، وأفضل ممارسات الأمان.

كيف يعمل رفع الملفات في PHP

عندما يقوم المستخدم بتحديد ملف وإرسال نموذج، يرسل المتصفح الملف إلى الخادم. PHP يتلقى الملف المرفوع من خلال $_FILES superglobal.

تتبع عملية التحميل عادةً الخطوات التالية:

  1. يقوم المستخدم بتحديد ملف من نموذج HTML.

  2. يرسل النموذج الملف باستخدام POST و بيانات متعددة الأجزاء/النموذج.

  3. PHP يقرأ الملف المرفوع من $_FILES.

  4. PHP يتحقق من صحة حالة خطأ التحميل وحجمه وامتداده ونوع MIME.

  5. يقوم PHP بإنشاء اسم ملف جديد وآمن.

  6. PHP ينقل الملف من التخزين المؤقت إلى مجلد التحميل الدائم.

  7. PHP يخزن معلومات الملف في MySQL.

  8. ويمكن للتطبيق لاحقًا عرض الملف أو تنزيله أو تحديثه أو حذفه.

يعتبر سير العمل هذا بسيطًا من حيث المفهوم، ولكن يجب التعامل مع رفع الملفات بعناية لأن الملفات المرفوعة يمكن أن تؤدي إلى مخاطر أمنية خطيرة إذا كان التحقق من الصحة ضعيفًا.

جدول قاعدة البيانات للملفات المرفوعة

قبل تخزين معلومات الملف في MySQL، تحتاج إلى جدول قاعدة بيانات. اسم الجدول الشائع هو التحميلات أو ملفات.

CREATE TABLE uploads (
    id INT AUTO_INCREMENT PRIMARY KEY,
    original_name VARCHAR(255) NOT NULL,
    stored_name VARCHAR(255) NOT NULL,
    file_path VARCHAR(500) NOT NULL,
    mime_type VARCHAR(150) NOT NULL,
    file_size INT NOT NULL,
    extension VARCHAR(20) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

ال original_name يخزن العمود الاسم الأصلي الذي تم تحميله بواسطة المستخدم. ال store_name يخزن العمود اسم الملف الآمن الذي تم إنشاؤه والمستخدم على الخادم.

ال file_path يخزن العمود المسار النسبي للملف. ال mime_type يخزن العمود نوع الملف المكتشف. ال file_size يخزن العمود حجم الملف بالبايت.

من الأفضل عادةً تخزين مسار الملف في قاعدة البيانات بدلاً من تخزين محتوى الملف الكامل مباشرة داخل MySQL. يعد تخزين الملفات على القرص والبيانات التعريفية في قاعدة البيانات أبسط وأكثر كفاءة للعديد من تطبيقات الويب.

PDO اتصال قاعدة البيانات

يمكن لـ PHP الاتصال بـ MySQL باستخدام PDO. PDO يدعم العبارات المحضرة، والتي تعتبر مهمة لإدراج معلومات الملف المرفوع في قاعدة البيانات بشكل آمن.

قم بإنشاء ملف باسم db.php:

<?php
$host = "localhost";
$dbname = "php_uploads";
$username = "root";
$password = "";

try {
    $pdo = new PDO(
        "mysql:host=$host;dbname=$dbname;charset=utf8mb4",
        $username,
        $password
    );

    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $exception) {
    die("Database connection failed.");
}
?>

في الإنتاج، يجب تخزين بيانات اعتماد قاعدة البيانات في متغيرات البيئة أو ملفات التكوين خارج الدليل العام.

ال utf8mb4 يوصى باستخدام مجموعة الأحرف لأنها تدعم النص متعدد اللغات بشكل صحيح.

HTML نموذج رفع الملف

لرفع الملفات، يجب استخدام النموذج HTML طريقة = "آخر" و enctype = "متعدد الأجزاء/بيانات النموذج". بدون التشفير الصحيح، لن يتم إرسال الملف بشكل صحيح.

<form method="post" action="upload.php" enctype="multipart/form-data">
    <label>Choose file</label>
    <input type="file" name="uploaded_file">

    <button type="submit">Upload</button>
</form>

اسم الإدخال تم التحميل_ملف سيتم استخدامه بواسطة PHP للوصول إلى الملف من $_FILES["uploaded_file"].

بالنسبة لعمليات تحميل الصور فقط، يمكن للنموذج استخدام الملف يقبل سمة لتحسين تجربة المستخدم.

<input type="file" name="uploaded_file" accept="image/jpeg,image/png,image/webp">

تساعد سمة القبول المتصفح على إظهار أنواع الملفات ذات الصلة، ولكنها ليست ميزة أمان. لا يزال يتعين على PHP التحقق من صحة الملف على جانب الخادم.

فهم $_FILES

عندما يتم تحميل ملف، يقوم PHP بتخزين معلومات عنه في ملف $_FILES صفيف.

<?php
print_r($_FILES["uploaded_file"]);
?>

تتضمن معلومات الملف المرفوع عادةً ما يلي:

  • اسم: اسم الملف الأصلي من جهاز الكمبيوتر الخاص بالمستخدم.

  • يكتب: نوع MIME الذي يرسله المتصفح.

  • tmp_name: الموقع المؤقت للملف الذي تم تحميله على الخادم.

  • خطأ: رمز خطأ التحميل.

  • مقاس: حجم الملف بالبايت.

ال tmp_name القيمة مهمة لأن PHP يقوم أولاً بتخزين الملفات المرفوعة مؤقتًا. للاحتفاظ بالملف بشكل دائم، يجب عليك نقله باستخدام move_uploaded_file().

رفع الملفات في PHP الأساسي

يتلقى البرنامج النصي للتحميل الأساسي الملف وينقله إلى مجلد التحميلات.

<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $tmpName = $_FILES["uploaded_file"]["tmp_name"];
    $fileName = $_FILES["uploaded_file"]["name"];

    move_uploaded_file($tmpName, __DIR__ . "/uploads/" . $fileName);

    echo "File uploaded.";
}
?>

يوضح هذا المثال البسيط الفكرة الأساسية، لكنه ليس آمنًا بدرجة كافية للتطبيقات الحقيقية. فهو يستخدم اسم الملف الأصلي ولا يتحقق من صحة نوع الملف أو حجمه أو خطأ التحميل.

في المشاريع الحقيقية، لا تثق أبدًا في اسم الملف الأصلي أو امتداد الملف دون التحقق من صحته. يجب أن يقوم نظام التحميل الآمن بإنشاء اسم ملف جديد والتحقق من صحة الملف المرفوع بعناية.

التحقق من أخطاء التحميل

PHP يوفر رموز خطأ التحميل من خلال $_FILES["file"]["error"]. تحقق دائمًا من هذه القيمة قبل معالجة الملف المرفوع.

<?php
$error = $_FILES["uploaded_file"]["error"];

if ($error !== UPLOAD_ERR_OK) {
    echo "Upload failed.";
    exit;
}
?>

تتضمن أخطاء التحميل الشائعة ما يلي:

  • UPLOAD_ERR_OK: اكتمل التحميل بنجاح.

  • UPLOAD_ERR_INI_SIZE: يتجاوز الملف إعداد upload_max_filesize في php.ini.

  • UPLOAD_ERR_FORM_SIZE: يتجاوز الملف القيمة MAX_FILE_SIZE من النموذج.

  • تحميل_ERR_PARTIAL: تم تحميل الملف جزئيًا فقط.

  • UPLOAD_ERR_NO_FILE: لم يتم تحميل أي ملف.

يساعدك التحقق من أخطاء التحميل على إرجاع رسائل أفضل وتجنب معالجة الملفات غير الكاملة أو غير الصالحة.

التحقق من حجم الملف

يمنع التحقق من حجم الملف المستخدمين من تحميل ملفات كبيرة جدًا. يمكن للملفات الكبيرة أن تهدر مساحة التخزين، أو تبطئ الخادم، أو تتجاوز حدود الاستضافة.

يسمح المثال التالي بملفات يصل حجمها إلى 2 ميغابايت:

<?php
$maxSize = 2 * 1024 * 1024;

$fileSize = $_FILES["uploaded_file"]["size"];

if ($fileSize > $maxSize) {
    echo "File is too large. Maximum size is 2 MB.";
    exit;
}
?>

يتم قياس حجم الملف بالبايت. التعبير 2 * 1024 * 1024 يعني 2 ميجا

في المشاريع الحقيقية، يعتمد حجم الملف المسموح به على حالة الاستخدام. قد يقتصر حجم صور الملف الشخصي على 1 أو 2 ميجابايت، بينما قد تسمح مستندات PDF أو السير الذاتية بأحجام أكبر.

التحقق من صحة امتداد الملف

امتداد الملف هو الجزء الذي يلي النقطة الأخيرة في اسم الملف، مثل jpg أو png أو pdf أو docx. يساعد التحقق من صحة الامتداد على تقييد عمليات التحميل لأنواع الملفات المسموح بها.

<?php
$allowedExtensions = ["jpg", "jpeg", "png", "webp", "pdf"];

$originalName = $_FILES["uploaded_file"]["name"];
$extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));

if (!in_array($extension, $allowedExtensions, true)) {
    echo "This file extension is not allowed.";
    exit;
}
?>

يعد التحقق من صحة الامتداد مفيدًا، ولكن لا ينبغي أن يكون الفحص الوحيد. يمكن إعادة تسمية الملف بامتداد مزيف. للتحقق من صحة أقوى، تحقق أيضًا من نوع MIME.

التحقق من صحة نوع MIME

يصف نوع MIME النوع الفعلي للملف، مثل image/jpeg، image/png، application/pdf، أو image/webp. يمكن لـ PHP اكتشاف نوع MIME باستخدام finfo_file().

<?php
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($_FILES["uploaded_file"]["tmp_name"]);

$allowedMimeTypes = [
    "image/jpeg",
    "image/png",
    "image/webp",
    "application/pdf"
];

if (!in_array($mimeType, $allowedMimeTypes, true)) {
    echo "This file type is not allowed.";
    exit;
}
?>

يعد التحقق من صحة نوع MIME أقوى من الثقة في المتصفح المقدم $_FILES["type"] القيمة لأنها تتفحص محتوى الملف بشكل مباشر أكثر.

بالنسبة لتحميلات الصور، يمكنك أيضًا استخدام عمليات التحقق الخاصة بالصور مثل getimagesize() للتأكد من أن الملف هو صورة حقيقية.

إنشاء أسماء الملفات الآمنة

قد يكون استخدام اسم الملف الأصلي محفوفًا بالمخاطر. وقد تحتوي على مسافات أو أحرف خاصة أو أسماء مكررة أو أنماط غير آمنة. الأسلوب الأفضل هو إنشاء اسم ملف عشوائي جديد.

<?php
$extension = "jpg";

$storedName = bin2hex(random_bytes(16)) . "." . $extension;
?>

يؤدي هذا إلى إنشاء اسم ملف عشوائي يصعب تخمينه ومن غير المحتمل أن يتعارض مع الملفات الموجودة.

يمكنك أيضًا إضافة بادئة:

<?php
$storedName = "upload_" . time() . "_" . bin2hex(random_bytes(8)) . "." . $extension;
?>

تساعد أسماء الملفات الآمنة على منع الكتابة فوق الملفات الموجودة وتقليل المشكلات الناجمة عن أسماء الملفات المقدمة من قبل المستخدم.

نقل الملفات المرفوعة

بعد التحقق من الصحة، يجب نقل الملف المرفوع من موقعه المؤقت إلى دليل التحميل الدائم باستخدام move_uploaded_file().

<?php
$uploadDir = __DIR__ . "/uploads/";

if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0755, true);
}

$destination = $uploadDir . $storedName;

if (!move_uploaded_file($_FILES["uploaded_file"]["tmp_name"], $destination)) {
    echo "Failed to move uploaded file.";
    exit;
}

echo "File moved successfully.";
?>

الوظيفة move_uploaded_file() تم تصميمه خصيصًا للملفات التي تم تحميلها ويساعد على التأكد من أن الملف جاء من عملية تحميل صالحة.

يجب أن يتمتع دليل التحميل بالأذونات الصحيحة. يجب أن يكون قابلاً للكتابة بواسطة التطبيق ولكن يجب ألا يسمح بتنفيذ البرامج النصية التي تم تحميلها PHP.

تخزين مسار الملف في MySQL

بعد نقل الملف بنجاح، قم بتخزين معلوماته في قاعدة البيانات. استخدم عبارة معدة لإدراج بيانات التعريف بأمان.

<?php
require "db.php";

$originalName = $_FILES["uploaded_file"]["name"];
$fileSize = $_FILES["uploaded_file"]["size"];
$filePath = "uploads/" . $storedName;

$statement = $pdo->prepare("
    INSERT INTO uploads (original_name, stored_name, file_path, mime_type, file_size, extension)
    VALUES (:original_name, :stored_name, :file_path, :mime_type, :file_size, :extension)
");

$statement->execute([
    "original_name" => $originalName,
    "stored_name" => $storedName,
    "file_path" => $filePath,
    "mime_type" => $mimeType,
    "file_size" => $fileSize,
    "extension" => $extension
]);

echo "File uploaded and saved in database.";
?>

تحتوي قاعدة البيانات الآن على معلومات حول الملف المرفوع. يتيح ذلك إدراج الملفات أو عرض الصور أو تنزيل المستندات أو حذف التحميلات أو توصيل الملفات بالمستخدمين والسجلات.

إكمال البرنامج النصي للتحميل

يجمع المثال التالي بين التحقق من الصحة والتسمية الآمنة ونقل الملفات وإدراج قاعدة البيانات في برنامج نصي واحد للتحميل.

<?php
require "db.php";

if ($_SERVER["REQUEST_METHOD"] !== "POST") {
    echo "Invalid request.";
    exit;
}

if (!isset($_FILES["uploaded_file"])) {
    echo "No file was uploaded.";
    exit;
}

$file = $_FILES["uploaded_file"];

if ($file["error"] !== UPLOAD_ERR_OK) {
    echo "Upload error.";
    exit;
}

$maxSize = 2 * 1024 * 1024;

if ($file["size"] > $maxSize) {
    echo "File is too large.";
    exit;
}

$allowedExtensions = ["jpg", "jpeg", "png", "webp", "pdf"];
$allowedMimeTypes = [
    "image/jpeg",
    "image/png",
    "image/webp",
    "application/pdf"
];

$originalName = $file["name"];
$extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));

if (!in_array($extension, $allowedExtensions, true)) {
    echo "File extension is not allowed.";
    exit;
}

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($file["tmp_name"]);

if (!in_array($mimeType, $allowedMimeTypes, true)) {
    echo "File type is not allowed.";
    exit;
}

$storedName = bin2hex(random_bytes(16)) . "." . $extension;

$uploadDir = __DIR__ . "/uploads/";

if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0755, true);
}

$destination = $uploadDir . $storedName;

if (!move_uploaded_file($file["tmp_name"], $destination)) {
    echo "Failed to save uploaded file.";
    exit;
}

$filePath = "uploads/" . $storedName;

$statement = $pdo->prepare("
    INSERT INTO uploads (original_name, stored_name, file_path, mime_type, file_size, extension)
    VALUES (:original_name, :stored_name, :file_path, :mime_type, :file_size, :extension)
");

$statement->execute([
    "original_name" => $originalName,
    "stored_name" => $storedName,
    "file_path" => $filePath,
    "mime_type" => $mimeType,
    "file_size" => $file["size"],
    "extension" => $extension
]);

echo "File uploaded successfully.";
?>

يعد هذا البرنامج النصي أكثر أمانًا من مثال التحميل الأساسي لأنه يتحقق من صحة الأخطاء والحجم والامتداد ونوع MIME واسم الملف ودليل التحميل وإدراج قاعدة البيانات.

عرض الملفات المرفوعة

بعد تخزين معلومات الملف في MySQL، يمكنك تحديد السجلات من قاعدة البيانات وعرضها على الصفحة.

<?php
require "db.php";

$statement = $pdo->query("
    SELECT id, original_name, file_path, mime_type, file_size, created_at
    FROM uploads
    ORDER BY id DESC
");

$files = $statement->fetchAll();
?>

<h1>Uploaded Files</h1>

<?php foreach ($files as $file): ?>
    <div>
        <p><?php echo htmlspecialchars($file["original_name"], ENT_QUOTES, "UTF-8"); ?></p>
        <p>Size: <?php echo (int) $file["file_size"]; ?> bytes</p>

        <a href="<?php echo htmlspecialchars($file["file_path"], ENT_QUOTES, "UTF-8"); ?>" target="_blank">Open File</a>
    </div>
<?php endforeach; ?>

عند عرض القيم من قاعدة البيانات، استخدم htmlspecialchars() للهروب من إخراج النص بأمان.

بالنسبة للصور، يمكنك عرض الملف المرفوع باستخدام علامة الصورة إذا كان نوع MIME عبارة عن صورة.

<?php if (str_starts_with($file["mime_type"], "image/")): ?>
    <img src="<?php echo htmlspecialchars($file["file_path"], ENT_QUOTES, "UTF-8"); ?>" alt="" width="200">
<?php endif; ?>

وهذا يجعل من الممكن إنشاء المعارض أو أنظمة صور الملفات الشخصية أو قوائم صور المنتجات أو صفحات إدارة المستندات.

تنزيل الملفات المرفوعة

في بعض الأحيان قد لا ترغب في وصول المستخدمين إلى الملفات مباشرة من خلال الروابط العامة. بدلاً من ذلك، يمكنك إنشاء برنامج نصي للتنزيل يتحقق من الأذونات أولاً، ثم يخدم الملف.

<?php
require "db.php";

$id = filter_input(INPUT_GET, "id", FILTER_VALIDATE_INT);

if (!$id) {
    die("Invalid file ID.");
}

$statement = $pdo->prepare("SELECT * FROM uploads WHERE id = :id LIMIT 1");
$statement->execute(["id" => $id]);

$file = $statement->fetch();

if (!$file) {
    die("File not found.");
}

$fullPath = __DIR__ . "/" . $file["file_path"];

if (!file_exists($fullPath)) {
    die("File missing from server.");
}

header("Content-Type: " . $file["mime_type"]);
header("Content-Disposition: attachment; filename=\"" . basename($file["original_name"]) . "\"");
header("Content-Length: " . filesize($fullPath));

readfile($fullPath);
exit;
?>

يكون هذا الأسلوب مفيدًا عندما تكون الملفات خاصة ويجب تنزيلها بواسطة المستخدمين المصرح لهم فقط.

قبل تقديم الملفات الخاصة، تحقق مما إذا كان المستخدم الذي قام بتسجيل الدخول لديه إذن للوصول إلى الملف.

تحديث ملف تم تحميله

في بعض التطبيقات، يحتاج المستخدمون إلى استبدال ملف تم تحميله بالفعل. على سبيل المثال، يمكن للمستخدم تحديث صورة الملف الشخصي أو استبدال مستند السيرة الذاتية.

عادةً ما تتبع عملية التحديث الخطوات التالية:

  1. ابحث عن سجل الملف الموجود في قاعدة البيانات.

  2. التحقق من صحة الملف الجديد الذي تم تحميله.

  3. انقل الملف الجديد إلى دليل التحميل.

  4. احذف الملف القديم من الخادم إذا لزم الأمر.

  5. قم بتحديث سجل قاعدة البيانات بمعلومات الملف الجديد.

يمكن أن يبدو استعلام التحديث المبسط كما يلي:

<?php
$statement = $pdo->prepare("
    UPDATE uploads
    SET original_name = :original_name,
        stored_name = :stored_name,
        file_path = :file_path,
        mime_type = :mime_type,
        file_size = :file_size,
        extension = :extension
    WHERE id = :id
");

$statement->execute([
    "id" => $id,
    "original_name" => $originalName,
    "stored_name" => $storedName,
    "file_path" => $filePath,
    "mime_type" => $mimeType,
    "file_size" => $fileSize,
    "extension" => $extension
]);
?>

عند استبدال الملفات، تأكد من عدم حذف الملف القديم حتى يتم تحميل الملف الجديد وحفظه بنجاح. يؤدي هذا إلى تجنب فقدان الملف القديم في حالة فشل التحميل الجديد.

حذف الملفات المرفوعة

يجب أن يؤدي حذف الملف المرفوع إلى إزالة سجل قاعدة البيانات والملف الفعلي من الخادم.

<?php
require "db.php";

$id = filter_input(INPUT_POST, "id", FILTER_VALIDATE_INT);

if (!$id) {
    die("Invalid file ID.");
}

$statement = $pdo->prepare("SELECT * FROM uploads WHERE id = :id LIMIT 1");
$statement->execute(["id" => $id]);

$file = $statement->fetch();

if (!$file) {
    die("File not found.");
}

$fullPath = __DIR__ . "/" . $file["file_path"];

$delete = $pdo->prepare("DELETE FROM uploads WHERE id = :id");
$delete->execute(["id" => $id]);

if (file_exists($fullPath)) {
    unlink($fullPath);
}

echo "File deleted successfully.";
?>

في التطبيقات الحقيقية، يجب حماية إجراءات الحذف عن طريق المصادقة والترخيص وحماية CSRF.

إذا كانت الملفات مهمة، فيمكنك استخدام منطق الحذف الناعم بدلاً من حذفها نهائيًا على الفور.

تحميل ملفات متعددة

يمكن لـ PHP أيضًا التعامل مع عمليات رفع الملفات المتعددة. يجب استخدام الإدخال HTML عديد ويجب أن يستخدم الاسم بين قوسين مربعين.

<form method="post" action="upload-multiple.php" enctype="multipart/form-data">
    <input type="file" name="files[]" multiple>
    <button type="submit">Upload Files</button>
</form>

يتلقى PHP ملفات متعددة كمصفوفات بالداخل $_FILES.

<?php
foreach ($_FILES["files"]["name"] as $index => $name) {
    $tmpName = $_FILES["files"]["tmp_name"][$index];
    $error = $_FILES["files"]["error"][$index];
    $size = $_FILES["files"]["size"][$index];

    if ($error !== UPLOAD_ERR_OK) {
        continue;
    }

    // Validate and move each file here
}
?>

يجب التحقق من صحة كل ملف على حدة. لا تفترض أن جميع الملفات صالحة لمجرد إرسال النموذج.

تعتبر التحميلات المتعددة مفيدة للمعارض وصور المنتجات ومجموعات المستندات والشهادات والمرفقات.

ربط التحميلات للمستخدمين أو المشاركات

في المشاريع الحقيقية، غالبًا ما تنتمي الملفات المرفوعة إلى سجل آخر. على سبيل المثال، تنتمي صورة الملف الشخصي إلى مستخدم، وصورة المنتج تنتمي إلى منتج، والمرفق ينتمي إلى رسالة.

يمكنك ربط التحميلات بالمستخدمين عن طريق إضافة ملف معرف المستخدم عمود.

ALTER TABLE uploads ADD user_id INT NULL;

ثم قم بتخزين معرف المستخدم الذي قام بتسجيل الدخول عند إدراج التحميل:

<?php
session_start();

$userId = $_SESSION["user_id"];

$statement = $pdo->prepare("
    INSERT INTO uploads (user_id, original_name, stored_name, file_path, mime_type, file_size, extension)
    VALUES (:user_id, :original_name, :stored_name, :file_path, :mime_type, :file_size, :extension)
");

$statement->execute([
    "user_id" => $userId,
    "original_name" => $originalName,
    "stored_name" => $storedName,
    "file_path" => $filePath,
    "mime_type" => $mimeType,
    "file_size" => $fileSize,
    "extension" => $extension
]);
?>

يسمح هذا للتطبيق بإظهار الملفات المرفوعة لكل مستخدم فقط.

تحقق دائمًا من الملكية قبل عرض الملفات الخاصة التي تم تحميلها أو تنزيلها أو تحديثها أو حذفها.

معاينة تحميل الصورة

بالنسبة لنماذج تحميل الصور، يمكن أن يعرض JavaScript معاينة قبل إرسال الملف. يؤدي هذا إلى تحسين تجربة المستخدم، ولكن لا يزال التحقق من جانب الخادم مطلوبًا.

<input type="file" id="imageInput" name="uploaded_file" accept="image/*">
<img id="preview" src="" alt="" width="200" style="display:none;">

<script>
document.getElementById("imageInput").addEventListener("change", function () {
    const file = this.files[0];

    if (!file) {
        return;
    }

    const preview = document.getElementById("preview");
    preview.src = URL.createObjectURL(file);
    preview.style.display = "block";
});
</script>

تساعد هذه المعاينة المستخدم فقط على رؤية الصورة المحددة. ولا يثبت أن الملف آمن. لا يزال يتعين على PHP التحقق من صحة الملف بعد التحميل.

PHP تكوين التحميلات

يتأثر سلوك الرفع في PHP أيضًا بتكوين الخادم. تتضمن الإعدادات المهمة ما يلي:

  • تحميلات الملف: تمكين أو تعطيل رفع الملفات.

  • upload_max_filesize: الحد الأقصى المسموح به لحجم الملف المرفوع.

  • post_max_size: الحد الأقصى لحجم طلب POST بالكامل.

  • الحد الأقصى لعدد تحميلات_الملفات: الحد الأقصى لعدد الملفات التي يمكن رفعها في طلب واحد.

  • الحد الأقصى لوقت التنفيذ: الحد الأقصى لوقت تنفيذ البرنامج النصي.

إذا كان البرنامج النصي PHP الخاص بك يسمح بملفات بحجم 10 ميغابايت ولكن upload_max_filesize تم ضبطه على 2 ميجابايت، فسيظل تكوين الخادم يرفض الملفات الأكبر حجمًا.

للحصول على ميزات تحميل أكبر، اضبط التكوين بعناية وتجنب السماح بأحجام ملفات غير محدودة.

ملاحظات أمنية لرفع الملفات في PHP

يعد رفع الملفات أحد أكثر الميزات حساسية في تطبيقات الويب. يمكن لنظام التحميل الضعيف أن يسمح للمهاجمين برفع الملفات القابلة للتنفيذ، أو استهلاك مساحة التخزين، أو الوصول إلى الملفات الخاصة.

تشمل الممارسات الأمنية المهمة ما يلي:

  • تحقق من أخطاء التحميل قبل معالجة الملفات.

  • الحد من امتدادات الملفات المسموح بها.

  • التحقق من صحة نوع MIME باستخدام finfo_file().

  • الحد من حجم الملف.

  • إنشاء أسماء ملفات عشوائية آمنة.

  • لا تثق في اسم الملف الأصلي.

  • لا تسمح بتحميل ملفات PHP أو البرامج النصية القابلة للتنفيذ.

  • قم بتخزين الملفات الخاصة خارج الدليل العام عندما يكون ذلك ممكنًا.

  • منع التنفيذ داخل مجلد التحميلات.

  • تحقق من أذونات المستخدم قبل تنزيل الإجراءات أو تحديثها أو حذفها.

  • استخدم حماية CSRF لتحميل النماذج وحذفها.

  • الهروب من أسماء الملفات عند عرضها في HTML.

بالنسبة لتحميلات الصور العامة، من المفيد أيضًا تغيير حجم الصور وإزالة البيانات التعريفية غير الضرورية وتخزين الإصدارات المحسنة.

كيف يتم استخدام تحميل الملف باستخدام MySQL في المشاريع الحقيقية

يتم استخدام رفع الملفات باستخدام MySQL في العديد من تطبيقات الويب الحقيقية. يتم تخزين الملف على الخادم أو خدمة التخزين، وتحتفظ قاعدة البيانات بالبيانات الوصفية اللازمة لإدارته.

تشمل الأمثلة الشائعة ما يلي:

  • صور الملف الشخصي للمستخدم.

  • استئناف أو تحميل السيرة الذاتية.

  • صور المنتج.

  • صور غلاف مشاركة المدونة.

  • أنظمة إدارة الوثائق.

  • معارض الصور.

  • الشهادات والوثائق الأكاديمية.

  • دعم مرفقات التذاكر.

  • صور مشروع المحفظة.

في الأنظمة الأكبر حجمًا، قد يتم تخزين التحميلات في التخزين السحابي مثل Amazon S3 أو خدمة تخزين كائنات أخرى، بينما يقوم MySQL بتخزين الملف URL والبيانات التعريفية.

تحميل الملف في أطر عمل PHP الحديثة

توفر أطر عمل PHP الحديثة مثل Laravel أدوات نظيفة لرفع الملفات والتحقق من صحتها وتخزينها وتكامل قاعدة البيانات. يمكن لـ Laravel التحقق من صحة الملفات، وتخزينها على أقراص محلية أو سحابية، وإنشاء المسارات، وربط التحميلات بالنماذج.

ومع ذلك، فإن تحميل ملف التعلم في PHP الخالص لا يزال مهمًا. يساعدك على فهم كيف $_FILES، التحقق من صحة التحميل، move_uploaded_file()تعمل مسارات الملفات وبيانات تعريف قاعدة البيانات خلف الكواليس.

بمجرد فهم سير العمل PHP الخالص، يصبح استخدام أدوات إطار العمل أسهل وأكثر وضوحًا.

خاتمة

يعد رفع الملفات في PHP باستخدام MySQL ميزة خلفية مهمة. فهو يسمح للتطبيقات بتلقي الملفات من المستخدمين والتحقق من صحتها وتخزينها بأمان على الخادم وحفظ معلومات الملف في قاعدة البيانات.

الخطوات الأساسية هي إنشاء نموذج تحميل، والقراءة $_FILES، والتحقق من أخطاء التحميل، والتحقق من صحة حجم الملف، والتحقق من صحة الامتداد ونوع MIME، وإنشاء اسم ملف آمن، ونقل الملف، وتخزين البيانات الوصفية في MySQL باستخدام العبارات المحضرة.

بعد تعلم هذا الموضوع، فإن الخطوة التالية هي التدرب على إنشاء نظام رفع صورة الملف الشخصي، أو مدير تحميل المستندات، أو معرض صور المنتج، أو نظام تنزيل ملفات خاص مع مصادقة المستخدم وأذوناته.