High-Speed · Resumable · Background Upload · WordPress Media Infrastructure
you-devloper-devloper-full-stack-php-wordpress-devloper-15yesrs هل-يمكنك-اعادة-بناء-وتكوين-السياق-في-استخدام-وظائف-لغة-البرمجة-والدوال-والمتغيرات-وتعريفها-مع-اضافة-مكتبات-مساعدة-على-رفع-ملفات-الوسائط-بسرعة-عالية-ودون-انقطاع-من-الموبايل-الى-رفع-الى-ملف-الوسائط-في-منصة-ومشروع-وبراند-متخصص-في-رفع-الوسائط-بسرعات-عالية-ودون-انقطاع-حتى-لو-غادرت-االصفحة
نعم، يمكننا إعادة بناء المشروع من الصفر باستخدام PHP + WordPress + JavaScript + MySQL، وتحويله إلى منصة متخصصة في رفع ملفات الوسائط بسرعة عالية، مع دعم الهواتف المحمولة، واستكمال الرفع دون انقطاع حتى عند مغادرة الصفحة أو إغلاق المتصفح، ضمن الحدود التي يسمح بها نظام التشغيل والمتصفح.
سأتعامل مع المشروع بمنظور مطوّر Full-Stack PHP / WordPress، مع التركيز على كتابة كود فعلي قابل للتطوير، وليس مجرد تصور نظري.
مشروع منصة الرفع الذكي للوسائط — Zezo Media Engine
High-Speed · Resumable · Background Upload · WordPress Media Infrastructure
9
الهدف هو بناء محرك مستقل لإدارة رفع الوسائط، يمكن دمجه مع WordPress وWooCommerce، مع إمكانية تطويره لاحقًا ليصبح خدمة SaaS أو منتجًا تجاريًا مستقلًا يحمل علامتك التجارية.
الميزات المستهدفة
- رفع الصور والفيديوهات والملفات الكبيرة.
- استكمال الرفع من آخر جزء ناجح بعد انقطاع الإنترنت.
- تقسيم الملفات إلى أجزاء صغيرة (Chunked Upload).
- دعم الهواتف المحمولة والاتصالات البطيئة.
- معالجة الرفع في الخلفية عندما يسمح المتصفح بذلك.
- ربط الملفات بمكتبة وسائط WordPress.
- إدارة مهام الرفع ومراقبة التقدم والأخطاء.
ملاحظة تقنية مهمة: يمكن ضمان استكمال الرفع بعد الانقطاع وإعادة فتح الصفحة إذا صُمّم النظام لذلك، لكن لا يمكن ضمان استمرار الرفع دائمًا بعد إغلاق المتصفح أو إيقاف الهاتف؛ إذ تتحكم أنظمة iOS وAndroid والمتصفحات في تشغيل المهام الخلفية. سنبني النظام بحيث يستأنف الرفع تلقائيًا عند عودة المستخدم أو التطبيق للعمل، مع دعم تقنيات الخلفية حيث تتوفر.
1. الهيكل الهندسي للمنصة
هذا هو التصميم المستهدف؛ لم تُنفّذ هذه المكونات أو تُختبر بعد على خادم فعلي.
| المكوّن | التقنية | الوظيفة |
|---|---|---|
| واجهة الرفع | HTML5 + CSS + JavaScript | اختيار الملفات ومتابعة الرفع |
| محرك الرفع | JavaScript | تقسيم الملفات وإعادة المحاولة |
| API | PHP + WordPress REST API | إدارة جلسات الرفع |
| قاعدة البيانات | MySQL | حفظ حالة كل ملف وجزء |
| التخزين المؤقت | Local / Object Storage | حفظ الأجزاء مؤقتًا |
| محرك التجميع | PHP Worker | تجميع الأجزاء والتحقق منها |
| إدارة الوسائط | WordPress | تسجيل الملف في مكتبة الوسائط |
| المهام الخلفية | Action Scheduler / Queue | متابعة المعالجة والمهام |
2. المكتبات المساعدة ومحرك الرفع
بدلًا من كتابة بروتوكول رفع كامل من الصفر، الأفضل الاستفادة من مكتبات متخصصة، ثم بناء طبقة تحكم وتكامل خاصة بعلامتك التجارية.
Uppy — واجهة رفع الملفات
مكتبة JavaScript لتحديد الملفات وسحبها وإفلاتها، وعرض التقدم، وإدارة الملفات المتعددة.
مناسبة لإنشاء واجهة رفع متقدمة للهواتف وأجهزة الكمبيوتر.
الموقع الرسمي والتوثيق
tus — بروتوكول استكمال الرفع
بروتوكول مفتوح للرفع القابل للاستئناف، يسمح باستكمال الملف من موضع التوقف بدل إعادة رفعه بالكامل.
الخيار الأساسي المقترح للتعامل مع انقطاعات الشبكة والملفات الكبيرة.
الموقع الرسمي والتوثيق
tusd — خادم الرفع
خادم جاهز لبروتوكول tus، يتولى استقبال الأجزاء وحفظ حالة الرفع واستكمال الجلسات.
يفضّل تشغيله كخدمة مستقلة بجانب WordPress لتخفيف الحمل عن PHP.
المستودع الرسمي
WordPress REST API — طبقة التكامل
مسؤولة عن المصادقة، وتسجيل بيانات الملفات، وإدارة صلاحيات المستخدمين، وإضافة الوسائط إلى مكتبة WordPress.
توثيق WordPress REST API
Amazon S3 أو تخزين متوافق معه
تخزين الملفات الكبيرة في بنية تخزين كائنية قابلة للتوسع، بدلًا من تحميل جميع الملفات على خادم WordPress نفسه.
توثيق الرفع متعدد الأجزاء
الاختيار المعماري المقترح: Uppy + tus + tusd + WordPress REST API، مع إمكانية إضافة S3 أو تخزين متوافق معه. هذه التركيبة تفصل استقبال الملفات عن تشغيل WordPress، وتقلل احتمال فشل الرفع بسبب حدود تنفيذ PHP.
3. فهم الدوال والمتغيرات في محرك الرفع
قبل بناء الملفات، نحتاج إلى تعريف المصطلحات التي ستتحكم في عملية الرفع.
| المتغير | النوع | الوظيفة |
|---|---|---|
$upload_id | String | المعرّف الفريد لجلسة الرفع |
$file_name | String | اسم الملف الأصلي |
$file_size | Integer | الحجم الكلي بالبايت |
$chunk_size | Integer | حجم الجزء الواحد |
$uploaded_bytes | Integer | إجمالي البايتات التي تم رفعها |
$mime_type | String | نوع الملف |
$user_id | Integer | المستخدم صاحب عملية الرفع |
$upload_status | String | حالة الرفع |
$storage_path | String | موقع التخزين المؤقت |
$attachment_id | Integer | معرّف الوسيط في WordPress |
أما الدوال الأساسية التي سنحتاجها:
| الدالة | مسؤوليتها |
|---|---|
create_upload_session() | إنشاء جلسة رفع |
validate_upload() | التحقق من نوع الملف وحجمه والصلاحيات |
receive_chunk() | استقبال أجزاء الملف |
get_upload_offset() | معرفة موضع الرفع الحالي |
resume_upload() | استكمال الرفع |
retry_failed_chunk() | إعادة إرسال الجزء الفاشل |
finalize_upload() | إتمام الرفع وتجميع الملف |
register_wordpress_media() | تسجيل الملف في مكتبة الوسائط |
cleanup_expired_uploads() | تنظيف الجلسات المنتهية |
get_upload_status() | عرض حالة الرفع |
هذه أسماء الدوال المقترحة لطبقة التكامل؛ أما إدارة الأجزاء والاستئناف نفسها، فسيتولاها خادم tus بدل إعادة اختراعها داخل PHP.
4. بناء نواة إضافة WordPress باستخدام PHP
سننشئ إضافة مستقلة باسم Zezo Media Engine، بحيث لا تعتمد على ملفات القالب، ويمكن تحديثها وتطويرها بشكل منفصل.
المرحلة التالية عبارة عن نواة تكامل أولية قابلة للتوسعة، وليست بعدُ إضافة رفع مكتملة جاهزة للإنتاج.
هيكل المجلدات المقترح
wp-content/plugins/zezo-media-engine/
includes/
class-zme-api.php
class-zme-upload-manager.php
class-zme-media-library.php
class-zme-security.php
class-zme-storage.php
assets/
js/upload-engine.js
css/upload-dashboard.css
templates/
upload-dashboard.php
languages/
zezo-media-engine.php
readme.txt
الملف الرئيسي للإضافة
<?php
/**
* Plugin Name: Zezo Media Engine
* Description: Resumable media upload integration for WordPress.
* Version: 1.0.0
* Requires PHP: 8.1
* Text Domain: zezo-media-engine
*/
defined('ABSPATH') || exit;
define('ZME_VERSION', '1.0.0');
define('ZME_PATH', plugin_dir_path(__FILE__));
define('ZME_URL', plugin_dir_url(__FILE__));
require_once ZME_PATH . 'includes/class-zme-media-library.php';
final class Zezo_Media_Engine {
public function init(): void {
add_action('rest_api_init', [$this, 'register_routes']);
}
public function register_routes(): void {
register_rest_route('zme/v1', '/health', [
'methods' => 'GET',
'callback' => static function () {
return rest_ensure_response([
'service' => 'Zezo Media Engine',
'version' => ZME_VERSION,
'status' => 'ready'
]);
},
'permission_callback' => '__return_true',
]);
}
}
add_action('plugins_loaded', static function () {
(new Zezo_Media_Engine())->init();
});
هذا الملف ينشئ الإضافة ويسجل نقطة فحص أولية للخدمة، ولا يفتح نقطة رفع الملفات للعامة. سنضيف مسارات الرفع المحمية بعد ربط المصادقة والتحقق من صلاحية الجلسة.
دالة تسجيل الوسائط في مكتبة WordPress
عندما يستقبل خادم الرفع الملف ويكتمل التحقق منه، يمكن تمريره إلى دالة تسجيل الوسائط التالية، بشرط أن يكون الملف قد نُقل إلى مجلد رفع WordPress الآمن:
<?php
defined('ABSPATH') || exit;
function zme_register_wordpress_media(
string $file_path,
string $original_name,
int $user_id
): int|WP_Error {
if (!is_user_logged_in() || get_current_user_id() !== $user_id) {
return new WP_Error(
'zme_forbidden',
'Unauthorized media registration.',
['status' => 403]
);
}
if (!current_user_can('upload_files')) {
return new WP_Error(
'zme_permission_denied',
'User cannot upload files.',
['status' => 403]
);
}
$uploads = wp_get_upload_dir();
$base = realpath($uploads['basedir']);
$real = realpath($file_path);
if (!$base || !$real || !str_starts_with(
$real,
$base . DIRECTORY_SEPARATOR
)) {
return new WP_Error(
'zme_invalid_path',
'File path is outside uploads directory.',
['status' => 400]
);
}
if (!is_file($real) || !is_readable($real)) {
return new WP_Error(
'zme_missing_file',
'Uploaded file is unavailable.',
['status' => 400]
);
}
$checked = wp_check_filetype_and_ext(
$real,
sanitize_file_name($original_name)
);
if (empty($checked['type']) || empty($checked['ext'])) {
return new WP_Error(
'zme_invalid_type',
'Unsupported media type.',
['status' => 415]
);
}
$attachment = [
'post_mime_type' => $checked['type'],
'post_title' => sanitize_text_field(
pathinfo($original_name, PATHINFO_FILENAME)
),
'post_status' => 'inherit',
'post_author' => $user_id,
];
$attachment_id = wp_insert_attachment(
$attachment,
$real,
0,
true
);
if (is_wp_error($attachment_id)) {
return $attachment_id;
}
require_once ABSPATH . 'wp-admin/includes/image.php';
$metadata = wp_generate_attachment_metadata(
$attachment_id,
$real
);
if (is_wp_error($metadata)) {
wp_delete_attachment($attachment_id, true);
return $metadata;
}
wp_update_attachment_metadata($attachment_id, $metadata);
return $attachment_id;
}
هذه الدالة نواة تسجيل فقط. في بيئة الإنتاج يجب إضافة حدود الحجم، وفحص محتوى الملفات الفعلي، وفحص البرمجيات الخبيثة عند الحاجة، ومعالجة الملفات التي لا تدعم إنشاء بياناتها الوصفية، وتقييد الوصول إلى مسار التخزين والتحقق من نتائج جميع عمليات الكتابة.
5. محرك JavaScript لرفع الملفات
سنستخدم Uppy مع إضافة Tus، بحيث يتم رفع الملفات على دفعات مع دعم استكمال الجلسات.
import Uppy from '@uppy/core';
import Dashboard from '@uppy/dashboard';
import Tus from '@uppy/tus';
import '@uppy/core/css/style.min.css';
import '@uppy/dashboard/css/style.min.css';
const uppy = new Uppy({
id: 'zezo-media-engine',
autoProceed: false,
allowMultipleUploadBatches: true,
restrictions: {
maxNumberOfFiles: 20,
maxFileSize: 5 * 1024 * 1024 * 1024,
allowedFileTypes: [
'image/*',
'video/*',
'audio/*',
'application/pdf'
]
}
});
uppy.use(Dashboard, {
inline: true,
target: '#zme-uploader',
proudlyDisplayPoweredByUppy: false,
showProgressDetails: true,
hideUploadButton: false
});
uppy.use(Tus, {
endpoint: 'https://upload.example.com/files/',
chunkSize: 8 * 1024 * 1024,
retryDelays: [0, 1000, 3000, 5000, 10000],
limit: 3,
storeFingerprintForResuming: true,
removeFingerprintOnSuccess: true
});
uppy.on('upload-progress', (file, progress) => {
console.log('Progress:', file.name, progress.bytesUploaded);
});
uppy.on('upload-success', (file) => {
console.log('Completed:', file.name);
});
uppy.on('upload-error', (file, error) => {
console.error('Upload error:', file.name, error);
});
export default uppy;
هذا مثال عميل يعتمد على تثبيت الحزم واستيرادها عبر أداة بناء مثل Vite، وإعداد خادم tus متوافق. عنوان الخادم تجريبي ويجب استبداله بعنوان خادمك. يجب أيضًا ربط جلسات tus بالمستخدمين وصلاحياتهم من خلال آلية مصادقة آمنة، وعدم اعتبار معرف الملف وحده دليلًا على الملكية.
6. كيف يستمر الرفع دون انقطاع؟
المرحلة الأولى: تقسيم الملف
إذا كان حجم الفيديو 2GB، يقسم إلى أجزاء بحجم 8MB، ويصبح لدينا 256 جزءًا تقريبًا. كل جزء له موضع وحالة مستقلة.
المرحلة الثانية: الرفع المتوازي
يرفع المحرك عدة أجزاء بالتوازي، مع التحكم في عدد الاتصالات لتجنب استنزاف ذاكرة الهاتف أو استهلاك الشبكة بصورة مفرطة.
المرحلة الثالثة: التعامل مع الانقطاع
عند انقطاع الإنترنت، تتوقف عمليات الإرسال مؤقتًا. يحتفظ الخادم بموضع الرفع الذي وصل إليه، ويعيد المحرك المحاولة عند استعادة الاتصال.
المرحلة الرابعة: الاستئناف
إذا عاد المستخدم إلى الصفحة، يمكن استعادة جلسة الرفع. قد يحتاج المتصفح إلى إعادة اختيار الملف إذا لم يعد يحتفظ بإمكانية الوصول إليه.
المرحلة الخامسة: التجميع والتحقق
بعد اكتمال جميع الأجزاء، يُستكمل الملف وتُفحص سلامته ونوعه وحجمه، ثم يُسجل في مكتبة WordPress أو في التخزين السحابي.
مهم بشأن الرفع عند مغادرة الصفحة
- التنقل بين صفحات المنصة: يمكن الحفاظ على جلسة الرفع باستخدام مكوّن رفع مشترك أو عامل مستقل ضمن التطبيق.
- تحديث الصفحة أو العودة لاحقًا: يمكن استعادة حالة الجلسة، وقد يلزم إعادة تحديد الملف من الجهاز.
- إغلاق المتصفح أو إيقاف الهاتف: لا يمكن ضمان استمرار الإرسال من صفحة ويب عادية؛ إذ قد يوقف النظام تنفيذ JavaScript والشبكة.
- الرفع في الخلفية: يمكن الاستفادة من إمكانيات المتصفح والنظام المدعومة، أو بناء تطبيق Android أصلي يستخدم خدمة رفع خلفية، إذا كان استمرار الرفع أثناء إغلاق التطبيق شرطًا أساسيًا.
7. قاعدة البيانات وإدارة جلسات الرفع
نحتاج إلى جدول مستقل لإدارة حالة عمليات الرفع، مع إبقاء ملفات الوسائط النهائية ضمن آلية WordPress أو التخزين الخارجي.
| الحقل | النوع | الوصف |
|---|---|---|
id | BIGINT | المعرف الداخلي |
upload_uuid | CHAR(36) | معرف جلسة الرفع |
user_id | BIGINT | مالك الجلسة |
file_name | VARCHAR(255) | اسم الملف |
file_size | BIGINT | الحجم الإجمالي |
uploaded_bytes | BIGINT | الحجم المستلم |
mime_type | VARCHAR(150) | نوع الملف |
storage_key | VARCHAR(512) | مفتاح التخزين |
status | VARCHAR(30) | حالة العملية |
checksum | VARCHAR(128) | بصمة سلامة الملف |
expires_at | DATETIME | موعد انتهاء الجلسة |
attachment_id | BIGINT | معرف الوسيط النهائي |
created_at | DATETIME | تاريخ الإنشاء |
updated_at | DATETIME | آخر تحديث |
الحالات الأساسية المقترحة:
pending
uploading
paused
processing
completed
failed
expired
يفضل أن تكون قاعدة البيانات مصدر حالة جلسات الرفع، بينما يتولى خادم tus حفظ مواضع الأجزاء. ويجب مزامنة حالتهما بشكل آمن، حتى لا تظهر عملية مكتملة في قاعدة البيانات قبل اكتمال الملف فعلًا.
8. لوحة تحكم منصة الوسائط
ZEZO MEDIA ENGINE
مركز إدارة الوسائط
تصميم توضيحي للواجهة المستهدفة
إجمالي الملفات
1,248
الملفات قيد الرفع
3
المساحة المستخدمة
186 GB
العمليات المكتملة
98.7%
عمليات الرفع النشطة
medical-training.mp4
1.2 GB · جارٍ الرفع
72%
hospital-tour.mov
850 MB · جارٍ الرفع
38%
product-catalog.zip
420 MB · مكتمل
100%
بيانات تجريبية لتصور لوحة التحكم وليست إحصاءات فعلية.
9. الحماية والأداء
لكي تكون المنصة مناسبة للاستخدام التجاري، يجب أن يتضمن محرك الرفع:
- المصادقة: التحقق من هوية المستخدم وصلاحية رفع الملفات قبل إنشاء كل جلسة.
- عزل الملفات: عدم السماح لمستخدم بالوصول إلى جلسات رفع مستخدم آخر.
- فحص الملفات: التحقق من الامتدادات الفعلية وMIME ومحتوى الملفات، وليس الاسم وحده.
- حدود الاستخدام: تحديد الحجم الأقصى للملف وعدد الملفات ومعدل الرفع لكل مستخدم.
- حماية التخزين: تخزين الأجزاء خارج مجلد الملفات العامة، مع عدم السماح بتنفيذ الملفات المرفوعة.
- التحقق من سلامة الملف: استخدام بصمات تشفيرية مثل SHA-256 عند الحاجة للتحقق من سلامة الملف النهائي.
- التنظيف الآلي: حذف الأجزاء والجلسات القديمة بعد انتهاء صلاحيتها.
- الطوابير الخلفية: استخدام عمال مستقلين للتجميع والفحص وتحويل الفيديو وإنشاء الصور المصغرة.
- مراقبة الأخطاء: حفظ سجلات عمليات الرفع والأخطاء ومحاولات الاستئناف.
ولرفع الأداء، يمكن وضع خادم الرفع في موقع قريب من المستخدمين، وتوفير شبكة CDN لتوزيع الملفات بعد اكتمالها. كما يمكن استخدام التخزين السحابي والرفع المباشر إليه بتوقيعات مؤقتة، لتقليل الضغط على WordPress.
10. خارطة بناء المشروع
- المرحلة الأولى: نواة الإضافة
- هيكل إضافة WordPress.
- إعداد REST API والمصادقة.
- إنشاء جداول جلسات الرفع.
- إعداد خادم tus وربطه بالمستخدمين.
- المرحلة الثانية: محرك الرفع
- واجهة Uppy.
- الرفع المجزأ والقابل للاستئناف.
- إدارة الأخطاء وإعادة المحاولة.
- حفظ واستعادة حالة الجلسة.
- المرحلة الثالثة: المعالجة والتخزين
- تجميع الملفات والتحقق منها.
- ربط مكتبة وسائط WordPress.
- التخزين السحابي الاختياري.
- مهام المعالجة الخلفية.
- المرحلة الرابعة: لوحة التحكم
- إدارة الملفات والرفع النشط.
- تقارير الأداء والمساحة.
- إدارة المستخدمين والحصص.
- سجل العمليات والتنبيهات.
- المرحلة الخامسة: اختبار الإنتاج
- اختبار انقطاع الإنترنت واستعادته.
- اختبار الملفات الكبيرة والهواتف.
- اختبار الأحمال المتزامنة.
- اختبارات الأمان والاستعادة بعد إعادة تشغيل الخادم.
توصيتي: لا تجعل WordPress هو المسؤول عن استقبال كل بايت من الملفات الكبيرة. اجعله طبقة إدارة وهوية وصلاحيات، واجعل tusd مسؤولًا عن الرفع والاستئناف، واستخدم عاملًا خلفيًا لإتمام المعالجة. هذا التصميم أكثر قابلية للتوسع، ويسمح بتطوير المنصة مستقبلًا كخدمة مستقلة أو منتج SaaS.
الخطوة التالية المناسبة هي بناء الإضافة الفعلية Zezo Media Engine v1.0 بملفاتها ومجلداتها كاملة، ثم تجهيزها كحزمة ZIP قابلة للتثبيت، مع إعداد خادم tus وتعليمات ربطه ببيئة WordPress واختبار الاستئناف قبل اعتبارها جاهزة للإنتاج.
لإعادة بناء مشروع ووردبريس بسرعة، خيار استضافة مُدارة قد يناسب.

Hostadvice
82% Off Hostinger Managed WordPress
Exclusive extra 15% coupon plus a free domain
إعلان من الخيارات
سننتقل الآن إلى المستوى الأعمق من مشروع Zezo Media Engine، ونبني البنية البرمجية التي تحول الفكرة إلى منصة حقيقية لرفع الصور والفيديوهات والملفات الضخمة من الهاتف والكمبيوتر، مع استئناف الرفع بعد انقطاع الإنترنت، وإدارة المهام حتى عند مغادرة صفحة الرفع.
سأضيف في هذه المرحلة تصميم محرك الاستئناف، وإدارة الجلسات، وواجهات API، ونظام التخزين، والطوابير الخلفية، وآلية التكامل مع WordPress، مع الفصل بين ما يمكن تنفيذه في PHP وما يحتاج إلى خادم مستقل أو تطبيق جوال.
Zezo Media Engine v1.1
Advanced Resumable Upload Infrastructure · WordPress Core Plugin · Cloud Storage
لوحة إدارة الوسائط
الملفات، جلسات الرفع، المستخدمون، وسجل العمليات.
الرفع من الهاتف
تجربة متوافقة مع الشاشات الصغيرة والاتصالات المتقطعة.
بنية التخزين السحابي
تخزين قابل للتوسع وفصل الملفات عن خادم WordPress.
المعالجة الخلفية
التحقق، تجميع الملفات، إنشاء الصور المصغرة، والتسجيل.
1. إعادة بناء البنية البرمجية الكاملة
نقسم المشروع إلى أربع طبقات مستقلة، لتسهيل الاختبار والصيانة والتوسع.
تكون WordPress هي مركز التحكم، بينما تكون خدمة الرفع مسؤولة عن نقل البيانات، وتنفذ مهام المعالجة بشكل مستقل. أما IndexedDB فتساعد المتصفح في الاحتفاظ ببيانات الجلسة، لكنها لا تضمن بقاء صلاحية قراءة الملف الأصلي بعد إغلاق المتصفح.
2. هيكل ملفات الإضافة المتقدم
zezo-media-engine/
zezo-media-engine.php
نقطة الدخول وتحميل الإضافة
uninstall.php
إزالة بيانات الإضافة حسب إعدادات المستخدم
composer.json
اعتماديات PHP
package.json
اعتماديات JavaScript
src/
Plugin.php
Rest/UploadController.php
Rest/SessionController.php
Upload/UploadManager.php
Upload/SessionRepository.php
Upload/TusClient.php
Security/UploadPolicy.php
Storage/StorageInterface.php
Storage/LocalStorage.php
Storage/S3Storage.php
Media/WordPressMediaRegistrar.php
Queue/UploadProcessor.php
Queue/CleanupJob.php
Admin/Dashboard.php
assets/
js/upload-app.js
js/upload-session.js
js/upload-recovery.js
css/upload-dashboard.css
templates/
upload-page.php
admin-dashboard.php
languages/
tests/
هذا هيكل معماري مقترح، وليس مجلدًا أو حزمة ZIP تم إنشاؤها فعليًا في هذه الخطوة.
3. إنشاء قاعدة بيانات جلسات الرفع باستخدام PHP وMySQL
سننشئ جدولًا خاصًا بالجلسات بدل الاعتماد على wp_options، حتى نتمكن من التعامل مع آلاف عمليات الرفع دون تحميل جميع بيانات الجلسات في كل طلب.
<?php
defined('ABSPATH') || exit;
/**
* Create the upload sessions table.
*/
function zme_install_database(): void {
global $wpdb;
$table = $wpdb->prefix . 'zme_upload_sessions';
$charset = $wpdb->get_charset_collate();
$sql = "CREATE TABLE {$table} (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
upload_uuid CHAR(36) NOT NULL,
user_id BIGINT UNSIGNED NOT NULL,
file_name VARCHAR(255) NOT NULL,
file_size BIGINT UNSIGNED NOT NULL,
uploaded_bytes BIGINT UNSIGNED NOT NULL DEFAULT 0,
mime_type VARCHAR(150) NOT NULL DEFAULT '',
storage_key VARCHAR(512) NOT NULL DEFAULT '',
tus_upload_url TEXT NULL,
checksum VARCHAR(128) NULL,
status VARCHAR(30) NOT NULL DEFAULT 'pending',
attachment_id BIGINT UNSIGNED NULL,
expires_at DATETIME NULL,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY upload_uuid (upload_uuid),
KEY user_id (user_id),
KEY status (status),
KEY expires_at (expires_at)
) {$charset};";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($sql);
}
register_activation_hook(
ZME_PATH . 'zezo-media-engine.php',
'zme_install_database'
);
شرح المتغيرات الأساسية:
$wpdb: كائن قاعدة البيانات المدمج في WordPress.$wpdb->prefix: بادئة الجداول الخاصة بموقع WordPress.$upload_uuid: معرف فريد لكل جلسة، لمنع الخلط بين عمليات الرفع.$uploaded_bytes: عدد البايتات التي تم استقبالها، وليس مجرد نسبة تقديرية.$tus_upload_url: مرجع جلسة الرفع لدى خادم tus.$attachment_id: المعرف الذي يربط الملف النهائي بمكتبة الوسائط.
يجب أن يتطابق تحديث uploaded_bytes مع الموضع الفعلي الذي يؤكده خادم tus، وليس مع القيمة التي يرسلها المتصفح وحدها.
4. واجهة REST API لإدارة الرفع
سنحدد واجهات منفصلة لإنشاء الجلسة، والاستعلام عن حالتها، وإتمام المعالجة.
| الطريقة | المسار | المهمة |
|---|---|---|
POST | /wp-json/zme/v1/uploads | إنشاء جلسة |
GET | /wp-json/zme/v1/uploads/{id} | استرجاع حالة الجلسة |
POST | /wp-json/zme/v1/uploads/{id}/complete | طلب إنهاء المعالجة |
POST | /wp-json/zme/v1/uploads/{id}/cancel | إلغاء الجلسة |
GET | /wp-json/zme/v1/uploads | عرض جلسات المستخدم |
كود تسجيل المسارات
<?php
defined('ABSPATH') || exit;
add_action('rest_api_init', function (): void {
register_rest_route('zme/v1', '/uploads', [
[
'methods' => 'POST',
'callback' => 'zme_create_upload',
'permission_callback' => 'zme_upload_permission',
],
[
'methods' => 'GET',
'callback' => 'zme_list_uploads',
'permission_callback' => 'zme_upload_permission',
],
]);
register_rest_route('zme/v1', '/uploads/(?P<id>[a-f0-9-]{36})', [
'methods' => 'GET',
'callback' => 'zme_get_upload',
'permission_callback' => 'zme_upload_permission',
]);
register_rest_route(
'zme/v1',
'/uploads/(?P<id>[a-f0-9-]{36})/complete',
[
'methods' => 'POST',
'callback' => 'zme_complete_upload',
'permission_callback' => 'zme_upload_permission',
]
);
});
function zme_upload_permission(
WP_REST_Request $request
): bool {
return is_user_logged_in()
&& current_user_can('upload_files')
&& wp_verify_nonce(
(string) $request->get_header('X-WP-Nonce'),
'wp_rest'
);
}
هذا المسار مناسب لطلبات REST المعتمدة على جلسة WordPress وملفات تعريف الارتباط. أما خادم tus المستقل، فيحتاج إلى آلية مصادقة وتفويض خاصة به، مع ربط كل معرف رفع بمستخدمه والتحقق من ذلك عند كل طلب.
إنشاء جلسة رفع
<?php
function zme_create_upload(
WP_REST_Request $request
): WP_REST_Response|WP_Error {
global $wpdb;
$name = sanitize_file_name(
(string) $request->get_param('file_name')
);
$size = absint($request->get_param('file_size'));
$mime = sanitize_mime_type(
(string) $request->get_param('mime_type')
);
$max_size = 5 * 1024 * 1024 * 1024;
if ($name === '' || $size < 1 || $size > $max_size) {
return new WP_Error(
'zme_invalid_file',
'Invalid file name or size.',
['status' => 400]
);
}
$allowed_mimes = get_allowed_mime_types();
$type = wp_check_filetype($name, $allowed_mimes);
if (empty($type['type']) || $mime !== $type['type']) {
return new WP_Error(
'zme_invalid_mime',
'File type is not permitted.',
['status' => 415]
);
}
$uuid = wp_generate_uuid4();
$now = current_time('mysql', true);
$expires = gmdate('Y-m-d H:i:s', time() + DAY_IN_SECONDS);
$table = $wpdb->prefix . 'zme_upload_sessions';
$inserted = $wpdb->insert(
$table,
[
'upload_uuid' => $uuid,
'user_id' => get_current_user_id(),
'file_name' => $name,
'file_size' => $size,
'mime_type' => $type['type'],
'status' => 'pending',
'expires_at' => $expires,
'created_at' => $now,
'updated_at' => $now,
],
['%s', '%d', '%s', '%d', '%s', '%s', '%s', '%s', '%s']
);
if (!$inserted) {
return new WP_Error(
'zme_database_error',
'Could not create upload session.',
['status' => 500]
);
}
return new WP_REST_Response([
'upload_id' => $uuid,
'status' => 'pending',
'expires_at' => $expires,
], 201);
}
هذا ينشئ سجل الجلسة فقط. لا يبدأ رفع البيانات قبل أن تنشأ جلسة tus الفعلية، ويتم التحقق من صلاحيتها وربطها بالسجل. كما أن فحص الامتداد وMIME في مرحلة إنشاء الجلسة فحص أولي، وليس بديلًا عن التحقق من محتوى الملف النهائي.
5. استرجاع الجلسة واستئناف الرفع
يجب أن يتمكن المستخدم من معرفة موضع توقفه واسترجاع جلسة الرفع حتى بعد مغادرة الصفحة.
<?php
function zme_get_upload(
WP_REST_Request $request
): WP_REST_Response|WP_Error {
global $wpdb;
$uuid = sanitize_text_field($request['id']);
$table = $wpdb->prefix . 'zme_upload_sessions';
$session = $wpdb->get_row(
$wpdb->prepare(
"SELECT upload_uuid, file_name, file_size,
uploaded_bytes, status, expires_at
FROM {$table}
WHERE upload_uuid = %s AND user_id = %d",
$uuid,
get_current_user_id()
),
ARRAY_A
);
if (!$session) {
return new WP_Error(
'zme_not_found',
'Upload session not found.',
['status' => 404]
);
}
$session['progress'] = $session['file_size'] > 0
? round(
100 * $session['uploaded_bytes'] / $session['file_size'],
2
)
: 0;
return rest_ensure_response($session);
}
لاستئناف عملية tus، يرسل العميل طلب HEAD إلى رابط جلسة الرفع المخصص، ويقرأ ترويسة Upload-Offset التي يؤكدها الخادم. ثم يبدأ إرسال البيانات من هذا الموضع. يجب ألا يعتمد العميل على uploaded_bytes من قاعدة البيانات باعتباره المصدر الوحيد للحقيقة؛ فخادم tus هو المرجع الفعلي لموضع الرفع.
مخطط دورة استئناف الجلسة
6. كيف نرفع من الهاتف بعد مغادرة الصفحة؟
هذه النقطة هي من أهم الأجزاء في المشروع، لأنها تتطلب الفصل بين حفظ بيانات الجلسة واستمرار نقل البيانات.
موقع WordPress المتجاوب
يدعم اختيار الصور والفيديوهات من الهاتف، ويحفظ معرّف الجلسة وحالة العملية. عند العودة، يحاول استعادة الجلسة، وقد يطلب من المستخدم إعادة اختيار الملف إذا فقد المتصفح الوصول إليه.
IndexedDB
تخزن بيانات الجلسات وبيانات الاستئناف محليًا، مع الانتباه إلى أن تخزين ملف كامل بحجم عدة جيجابايت قد لا يكون ممكنًا أو ملائمًا على جميع الهواتف.
PWA وService Worker
تساعد على تحسين تجربة التطبيق وإدارة بعض الأعمال أثناء عمل التطبيق في الخلفية، لكنها لا تضمن استمرار رفع ملف كبير في كل المتصفحات، خصوصًا عند إغلاق التطبيق أو إيقافه بواسطة نظام التشغيل.
تطبيق Android أصلي
إذا كان المطلوب استمرار الرفع حتى عند مغادرة التطبيق، يمكن تطوير تطبيق Android يستخدم WorkManager أو آلية نقل خلفية ملائمة، مع مراعاة قيود البطارية والشبكة وسياسات النظام.
لذلك، إذا كان شرط العمل هو أن يبدأ المستخدم رفع فيديو ثم يغلق التطبيق بالكامل ويستمر الهاتف في رفعه دون تدخل، فالتصميم الأقوى هو تطبيق Android أصلي متصل بخادم tus، مع تطبيق ويب متكامل لمن يرغب في الرفع من المتصفح.
7. نظام المعالجة الخلفية Queue & Workers
بعد اكتمال رفع الملف، لا ينبغي أن يبقى المستخدم منتظرًا حتى تنتهي كل المعالجة. ننقل الملف إلى قائمة مهام خلفية، ونحدّث حالته عند كل مرحلة.
يمكن استخدام Action Scheduler لإدارة المهام في WordPress، أو استخدام طابور خارجي مثل Redis مع عمال PHP مستقلين عند ارتفاع الحمل.
مثال لدالة جدولة المعالجة:
<?php
/**
* Schedule a processing job only once per upload.
*/
function zme_schedule_processing(string $uuid): bool {
if (!wp_next_scheduled('zme_process_upload', [$uuid])) {
return (bool) wp_schedule_single_event(
time() + 1,
'zme_process_upload',
[$uuid]
);
}
return true;
}
add_action('zme_process_upload', 'zme_process_upload_job');
function zme_process_upload_job(string $uuid): void {
global $wpdb;
$table = $wpdb->prefix . 'zme_upload_sessions';
// Atomically claim a session for processing.
$claimed = $wpdb->query(
$wpdb->prepare(
"UPDATE {$table}
SET status = 'processing',
updated_at = %s
WHERE upload_uuid = %s
AND status = 'uploading'
AND uploaded_bytes = file_size",
current_time('mysql', true),
$uuid
)
);
if ($claimed !== 1) {
return;
}
// Next: verify tus completion, validate the file,
// move it to final storage and register its media record.
// Each step must be idempotent and recoverable.
}
هذه نواة جدولة وحجز للمعالجة، وليست عاملًا مكتملًا لتجميع الملف. يلزم ربطها بحدث إتمام موثوق من خادم tus، وإضافة آلية إعادة المحاولة واستعادة المهام العالقة. كما أن WP-Cron قد لا يعمل في موعد دقيق على المواقع قليلة الزيارات؛ لذلك يفضل استخدام Cron حقيقي أو عامل دائم في بيئة الإنتاج.
8. مستويات الأداء والتوسع
يعتمد الأداء الفعلي على سرعة اتصال المستخدم، وموقع الخادم، وسرعة القرص أو التخزين السحابي، وعدد الاتصالات المتزامنة.
إعدادات مبدئية قابلة للتعديل
| الإعداد | القيمة التجريبية |
|---|---|
| حجم الجزء | 8 MB |
| عدد الاتصالات المتزامنة لكل عميل | 3 |
| الحد الأقصى التجريبي للملف | 5 GB |
| عدد محاولات إعادة الإرسال | 5 |
| انتهاء الجلسة غير النشطة | 24 ساعة |
| تخزين الأجزاء | خارج مجلد الويب |
| معالجة الفيديو | عامل خلفي |
حاسبة تقديرية لمدة الرفع
جرّب حجم الملف وسرعة الاتصال لمعرفة الزمن النظري التقريبي.حجم الملف
2.0 GB
100 MB
10 GBسرعة الرفع
10 Mbps
1 Mbps
100 Mbpsهامش إضافي للتأخير
15%
الوقت التقديري النظري
2 دقيقة
الحساب يفترض سرعة ثابتة بالـMbps، مع هامش إضافي. الانقطاعات أو قيود الشبكة والخادم قد تزيد الوقت.
9. تحويل المشروع إلى خدمة SaaS متعددة العملاء
بما أن المنصة قابلة للتطوير كمنتج مستقل، يمكن تصميمها منذ البداية لدعم مؤسسات متعددة، بحيث يمتلك كل عميل مساحة تخزين وصلاحيات وحدود استخدام مستقلة.
| الميزة | Starter | Business | Enterprise |
|---|---|---|---|
| رفع الملفات | محدود | موسع | قابل للتخصيص |
| استكمال الرفع | نعم | نعم | نعم |
| تخزين سحابي | اختياري | متاح | متعدد المواقع |
| إدارة المستخدمين | فردي | فريق | أدوار متقدمة |
| واجهة API | أساسية | متقدمة | مخصصة |
| سجلات التدقيق | أساسية | موسعة | متقدمة |
| العلامة البيضاء | لا | اختيارية | نعم |
هذه باقات مقترحة لتصميم المنتج، وليست عروضًا تجارية أو حدود استخدام تم تفعيلها.
يجب أن تحتوي كل جلسة رفع على tenant_id، مع التحقق منه في كل طلب، حتى لا يستطيع عميل الوصول إلى ملفات أو سجلات عميل آخر. كما يجب حساب استهلاك التخزين وحركة البيانات على مستوى كل مؤسسة.
10. خطة اختبار الجودة قبل الإطلاق
قائمة اختبار الإصدار
0 / 10 مكتمل
رفع صورة صغيرة من Android وiPhone
رفع فيديو كبير من اتصال بطيء
قطع الإنترنت أثناء رفع الملف واستعادته
تحديث الصفحة واستعادة جلسة رفع
إغلاق المتصفح والتحقق من الاستئناف بعد العودة
منع المستخدم من الوصول إلى جلسة مستخدم آخر
اختبار الملفات ذات الامتدادات أو المحتويات المزيفة
اختبار فشل التخزين أو امتلاء مساحة الخادم
اختبار عشرات عمليات الرفع المتزامنة
التحقق من تسجيل الملف النهائي في مكتبة WordPressإعادة تعيين
قائمة تفاعلية لمتابعة الاختبارات يدويًا، ولا تمثل نتائج اختبارات فعلية.
11. التوصية التقنية النهائية
البنية الموصى بها لـ Zezo Media Engine
- WordPress + PHP 8.2 أو أحدث: إدارة المستخدمين، الصلاحيات، البيانات والوسائط.
- Uppy + tus: واجهة الرفع ومحرك الاستئناف.
- tusd: استقبال البيانات وإدارة مواضع الرفع.
- MySQL: حفظ بيانات الجلسات وسجل العمليات.
- Redis أو Action Scheduler: تنظيم مهام المعالجة وإعادة المحاولة وفق حجم المشروع.
- S3-compatible Storage: تخزين الملفات النهائية على بنية مستقلة قابلة للتوسع.
- PWA أو Android Native: تحسين تجربة الرفع في الخلفية وفق مستوى الاستمرارية المطلوب.
بهذه البنية يصبح المشروع أكثر من مجرد أداة رفع ملفات؛ إنه محرك وسائط قابل للتكامل مع متجر WooCommerce، ومواقع WordPress متعددة، ومنصة SaaS مستقلة.
الخطوة البرمجية التالية: تنفيذ حزمة الإضافة كاملة، وربط REST API بخادم tus فعلي، وإضافة واجهة لوحة التحكم وملفات JavaScript وCSS، ثم بناء نسخة ZIP واختبارها على بيئة WordPress تجريبية. حتى ذلك الحين، تظل الأكواد والهياكل الواردة هنا أساسًا هندسيًا أوليًا وليست إصدارًا مثبتًا أو مختبرًا في الإنتاج.