any inconvenience caused.
حل أخطاء PHP – دليل شامل 🚀
سأقدم لك حلولاً شاملة لأخطاء PHP مع توضيح الأسباب والحلول لكل حالة:
📌 1. خطأ 500 Internal Server Error
✅ السبب الأكثر شيوعاً:
php
// ❌ خطأ في بناء الجملة (Syntax Error)
<?php
if ($x = 5) // نسيان القوس المغلق
echo "Hello";
echo "World"; // هذا السطر خارج الشرط
?>
🔍 الأسباب المحتملة والحلول:
أ) خطأ في بناء الجملة (Parse Error)
php
// ❌ الكود الخاطئ <?php $name = "Ahmed echo $name; // خطأ: سلسلة غير مغلقة ?>
php
// ✅ الحل الصحيح <?php $name = "Ahmed"; echo $name; ?>
ب) خطأ في تضمين الملفات
php
// ❌ الكود الخاطئ
<?php
include("config.php"); // الملف غير موجود
require("database.php"); // الملف غير موجود → خطأ قاتل
?>
php
// ✅ الحل الصحيح
<?php
// التحقق من وجود الملف قبل التضمين
if (file_exists("config.php")) {
include("config.php");
} else {
die("الملف config.php غير موجود");
}
// استخدام require_once لمنع التضمين المكرر
require_once("database.php");
?>
ج) مشاكل في ملف .htaccess
apache
# ❌ .htaccess خاطئ RewriteEngine On RewriteRule ^products/(.*)$ product.php?id=$1 # نسيان [L]
apache
# ✅ .htaccess صحيح RewriteEngine On RewriteRule ^products/(.*)$ product.php?id=$1 [L,QSA]
📌 2. أخطاء الاتصال بقاعدة البيانات
✅ خطأ: Connection failed: Access denied for user
php
// ❌ الكود الخاطئ <?php $host = "localhost"; $user = "root"; $pass = ""; // كلمة المرور فارغة لكن قاعدة البيانات تطلب كلمة مرور $db = "my_database"; $conn = new mysqli($host, $user, $pass, $db); // خطأ: Access denied for user 'root'@'localhost' ?>
php
// ✅ الحل الصحيح
<?php
$host = "localhost";
$user = "root";
$pass = "your_actual_password"; // إضافة كلمة المرور الصحيحة
$db = "my_database";
// إضافة معالجة الأخطاء
try {
$conn = new mysqli($host, $user, $pass, $db);
if ($conn->connect_error) {
throw new Exception("فشل الاتصال: " . $conn->connect_error);
}
echo "تم الاتصال بنجاح";
} catch (Exception $e) {
// تسجيل الخطأ في ملف السجلات بدلاً من عرضه للمستخدم
error_log($e->getMessage());
echo "حدث خطأ في الاتصال، يرجى المحاولة لاحقاً";
}
?>
📌 3. أخطاء المتغيرات غير المعرفة
✅ خطأ: Notice: Undefined variable
php
// ❌ الكود الخاطئ
<?php
function calculateTotal($price) {
$tax = 0.15;
// المتغير $discount غير معرف
$total = $price + ($price * $tax) - $discount; // تحذير!
return $total;
}
echo calculateTotal(100);
?>
php
// ✅ الحل الصحيح - الطريقة الأولى (تعريف المتغير)
<?php
function calculateTotal($price, $discount = 0) { // إضافة قيمة افتراضية
$tax = 0.15;
$total = $price + ($price * $tax) - $discount;
return $total;
}
echo calculateTotal(100, 10); // 105
?>
php
// ✅ الحل الصحيح - الطريقة الثانية (التحقق من وجود المتغير)
<?php
function calculateTotal($price) {
$tax = 0.15;
$discount = isset($discount) ? $discount : 0; // التحقق
$total = $price + ($price * $tax) - $discount;
return $total;
}
?>
📌 4. أخطاء المصفوفات (Array Errors)
✅ خطأ: Undefined array key
php
// ❌ الكود الخاطئ
<?php
$user = [
'name' => 'Ahmed',
'email' => 'ahmed@email.com'
];
echo $user['age']; // خطأ: المفتاح age غير موجود
?>
php
// ✅ الحل الصحيح - طريقة 1
<?php
$user = [
'name' => 'Ahmed',
'email' => 'ahmed@email.com'
];
// التحقق من وجود المفتاح
if (isset($user['age'])) {
echo $user['age'];
} else {
echo "العمر غير محدد";
}
?>
php
// ✅ الحل الصحيح - طريقة 2 (PHP 7+)
<?php
$user = [
'name' => 'Ahmed',
'email' => 'ahmed@email.com'
];
// استخدام null coalescing operator
$age = $user['age'] ?? "غير محدد";
echo $age; // "غير محدد"
?>
📌 5. أخطاء الجلسات (Session Errors)
✅ خطأ: Cannot send session cookie - headers already sent
php
// ❌ الكود الخاطئ <?php echo "مرحباً"; // إرسال محتوى قبل بدء الجلسة session_start(); // خطأ! تم إرسال الهيدرات بالفعل $_SESSION['user'] = 'Ahmed'; ?>
php
// ✅ الحل الصحيح - الطريقة الأولى <?php // بدء الجلسة في بداية الملف session_start(); echo "مرحباً"; $_SESSION['user'] = 'Ahmed'; ?>
php
// ✅ الحل الصحيح - الطريقة الثانية (اختبار احترافي) <?php // استخدام Output Buffering ob_start(); // بدء التخزين المؤقت session_start(); echo "مرحباً"; $_SESSION['user'] = 'Ahmed'; ob_end_flush(); // إرسال المخرجات بعد الجلسة ?>
📌 6. أخطاء الملفات (File Upload Errors)
✅ خطأ: File upload error - UPLOAD_ERR_INI_SIZE
php
// ❌ الكود الخاطئ
<?php
if ($_FILES['image']['error'] == 0) {
$tmp_name = $_FILES['image']['tmp_name'];
move_uploaded_file($tmp_name, "uploads/" . $_FILES['image']['name']);
}
?>
php
// ✅ الحل الصحيح - معالجة شاملة
<?php
// إعدادات في php.ini
ini_set('upload_max_filesize', '20M');
ini_set('post_max_size', '20M');
ini_set('max_execution_time', 300);
// التحقق من رفع الملف
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['image'];
$allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
$max_size = 5 * 1024 * 1024; // 5MB
// التحقق من النوع
if (!in_array($file['type'], $allowed_types)) {
die("نوع الملف غير مسموح");
}
// التحقق من الحجم
if ($file['size'] > $max_size) {
die("حجم الملف كبير جداً");
}
// إنشاء اسم فريد للملف
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$new_name = time() . '_' . uniqid() . '.' . $ext;
$destination = "uploads/" . $new_name;
if (move_uploaded_file($file['tmp_name'], $destination)) {
echo "تم رفع الملف بنجاح: " . $new_name;
} else {
echo "فشل رفع الملف";
}
} else {
// التعامل مع أخطاء الرفع
switch ($_FILES['image']['error']) {
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
echo "الملف كبير جداً";
break;
case UPLOAD_ERR_PARTIAL:
echo "تم رفع الملف بشكل ناقص";
break;
case UPLOAD_ERR_NO_FILE:
echo "لم يتم اختيار ملف";
break;
default:
echo "حدث خطأ غير معروف";
}
}
?>
📌 7. أخطاء الـ Class/Object
✅ خطأ: Call to undefined method
php
// ❌ الكود الخاطئ
<?php
class User {
private $name;
public function __construct($name) {
$this->name = $name;
}
}
$user = new User("Ahmed");
echo $user->getName(); // خطأ! الطريقة غير موجودة
?>
php
// ✅ الحل الصحيح
<?php
class User {
private $name;
public function __construct($name) {
$this->name = $name;
}
// إضافة الطريقة المفقودة
public function getName() {
return $this->name;
}
// إضافة метод __call للتعامل مع الطرق غير الموجودة
public function __call($method, $arguments) {
if ($method === 'get' . ucfirst($this->name)) {
return $this->name;
}
throw new Exception("الطريقة $method غير موجودة");
}
}
$user = new User("Ahmed");
echo $user->getName(); // "Ahmed"
?>
📌 8. أخطاء SQL Injection (أمن المعلومات)
❌ الكود غير الآمن:
php
<?php $id = $_GET['id']; // بيانات من المستخدم $query = "SELECT * FROM users WHERE id = $id"; // ثغرة أمنية! $result = mysqli_query($conn, $query); ?>
✅ الحلول الآمنة:
الطريقة 1: Prepared Statements (MySQLi)
php
<?php
$id = $_GET['id'];
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $id); // "i" = integer
$stmt->execute();
$result = $stmt->get_result();
?>
الطريقة 2: Prepared Statements (PDO)
php
<?php
$id = $_GET['id'];
try {
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $id]);
$result = $stmt->fetchAll();
} catch (PDOException $e) {
error_log($e->getMessage());
echo "حدث خطأ في قاعدة البيانات";
}
?>
📌 9. أخطاء XSS (Cross-Site Scripting)
❌ الكود غير الآمن:
php
<?php $user_input = $_GET['message']; echo "رسالتك: " . $user_input; // خطير! ?>
✅ الحلول الآمنة:
php
<?php $user_input = $_GET['message']; // استخدام htmlspecialchars echo "رسالتك: " . htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8'); // أو استخدام strip_tags (إزالة الـ HTML كلياً) echo "رسالتك: " . strip_tags($user_input); // أو استخدام filter_var echo "رسالتك: " . filter_var($user_input, FILTER_SANITIZE_STRING); ?>
📌 10. أخطاء الأداء
❌ كود بطيء:
php
<?php
// استعلام داخل حلقة - مشكلة N+1
$users = $db->query("SELECT * FROM users");
while ($user = $users->fetch_assoc()) {
$orders = $db->query("SELECT * FROM orders WHERE user_id = " . $user['id']);
// معالجة الطلبات
}
?>
✅ الحل المحسّن:
php
<?php
// استخدام JOIN لاستعلام واحد
$sql = "
SELECT u.*, o.*
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
";
$results = $db->query($sql);
// أو استخدام caching
$cache_key = 'users_with_orders';
$data = $cache->get($cache_key);
if (!$data) {
$data = $db->query($sql)->fetchAll();
$cache->set($cache_key, $data, 3600); // تخزين لمدة ساعة
}
?>
📌 11. أخطاء التكوين (php.ini)
✅ مشاكل شائعة:
ini
; ❌ إعدادات غير مناسبة memory_limit = 8M upload_max_filesize = 2M max_execution_time = 30 display_errors = On ; عرض الأخطاء في الإنتاج error_reporting = E_ALL
ini
; ✅ إعدادات محسّنة للإنتاج memory_limit = 256M upload_max_filesize = 20M post_max_size = 20M max_execution_time = 300 display_errors = Off ; إخفاء الأخطاء في الإنتاج log_errors = On error_log = /var/log/php_errors.log error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT ; ✅ إعدادات التطوير ; display_errors = On ; error_reporting = E_ALL
🛠️ أدوات تصحيح الأخطاء في PHP
php
<?php
// 1. دالة مخصصة للـ Debugging
function debug($var, $die = false) {
echo "<pre style='background:#f4f4f4;padding:10px;border:1px solid #ddd;'>";
echo "<strong>Debug:</strong><br>";
var_dump($var);
echo "</pre>";
if ($die) die();
}
// 2. تسجيل الأخطاء في ملف
function logError($message, $file = 'error.log') {
$log = date('Y-m-d H:i:s') . " - " . $message . "\n";
file_put_contents($file, $log, FILE_APPEND);
}
// 3. معالج أخطاء مخصص
set_error_handler(function($errno, $errstr, $errfile, $errline) {
$message = "خطأ [$errno] $errstr في $errfile السطر $errline";
logError($message);
if (ini_get('display_errors')) {
echo "<b>خطأ:</b> $errstr في <b>$errfile</b> السطر $errline";
}
});
// 4. معالج استثناءات مخصص
set_exception_handler(function($exception) {
$message = "استثناء: " . $exception->getMessage();
$message .= " في " . $exception->getFile();
$message .= " السطر " . $exception->getLine();
logError($message);
if (ini_get('display_errors')) {
echo "<b>استثناء:</b> " . $exception->getMessage();
}
});
?>
📝 ملخص سريع لحل الأخطاء:
| الخطأ | الحل السريع |
|---|---|
| 500 Internal Server Error | تحقق من الأخطاء في ملف error_log، تأكد من صلاحيات الملفات |
| Parse Error | تأكد من إغلاق جميع الأقواس والفواصل والعلامات |
| Undefined Variable | استخدم isset() أو ?? (null coalescing) |
| Undefined Index | استخدم array_key_exists() أو isset() |
| Headers Already Sent | استخدم ob_start() أو تأكد من عدم وجود مخرجات قبل session_start() |
| Connection Errors | تحقق من بيانات الاتصال، استخدم try-catch |
| File Upload Errors | تحقق من الإعدادات في php.ini، استخدم أنواع الملفات المسموحة |
| SQL Injection | استخدم Prepared Statements |
| XSS | استخدم htmlspecialchars() أو strip_tags() |
🎯 هل لديك خطأ محدد تواجهه الآن؟
ارسل لي:
- الكود المسبب للخطأ
- رسالة الخطأ كاملة
- بيئة التشغيل (إصدار PHP، نظام التشغيل)
وسأعطيك حلًا مخصصًا فوراً! 🚀
📚 من حلول أخطاء PHP – دليل شامل ومتقدم 🚀
سأقدم لك من الأخطاء الشائعة والحلول المتقدمة مع أمثلة عملية:
📌 12. أخطاء التعامل مع التواريخ والوقت
✅ خطأ: Warning: date(): It is not safe to rely on the system's timezone settings
php
// ❌ الكود الخاطئ
<?php
echo date('Y-m-d H:i:s'); // تحذير: المنطقة الزمنية غير محددة
?>
php
// ✅ الحل الصحيح - الطريقة الأولى
<?php
// تعيين المنطقة الزمنية في بداية الملف
date_default_timezone_set('Asia/Riyadh'); // أو 'Asia/Dubai'
echo date('Y-m-d H:i:s');
// أو استخدام UTC
date_default_timezone_set('UTC');
echo date('Y-m-d H:i:s');
?>
php
// ✅ الحل الصحيح - الطريقة الثانية (استخدام DateTime)
<?php
$datetime = new DateTime('now', new DateTimeZone('Asia/Riyadh'));
echo $datetime->format('Y-m-d H:i:s');
// تحويل بين المناطق الزمنية
$utc_time = new DateTime('now', new DateTimeZone('UTC'));
$riyadh_time = $utc_time->setTimezone(new DateTimeZone('Asia/Riyadh'));
echo $riyadh_time->format('Y-m-d H:i:s');
?>
✅ مشاكل حساب التواريخ
php
// ❌ حساب خاطئ للتواريخ <?php $date1 = "2024-01-01"; $date2 = "2024-01-31"; $diff = strtotime($date2) - strtotime($date1); $days = $diff / (60 * 60 * 24); // قد يعطي نتائج غير دقيقة مع التوقيت الصيفي ?>
php
// ✅ الحل الصحيح باستخدام DateTime
<?php
$date1 = new DateTime('2024-01-01');
$date2 = new DateTime('2024-01-31');
$interval = $date1->diff($date2);
echo "الفرق: " . $interval->days . " أيام";
echo "الفرق: " . $interval->m . " شهور";
echo "الفرق: " . $interval->y . " سنوات";
// إضافة/طرح تواريخ
$future = (new DateTime())->modify('+30 days');
$past = (new DateTime())->modify('-2 months');
?>
📌 13. أخطاء JSON
✅ خطأ: json_decode(): expects parameter 1 to be string, object given
php
// ❌ الكود الخاطئ <?php $data = ['name' => 'Ahmed', 'age' => 30]; $json = json_decode($data); // خطأ! يجب أن تكون string ?>
php
// ✅ الحل الصحيح
<?php
$data = ['name' => 'Ahmed', 'age' => 30];
// تحويل المصفوفة إلى JSON أولاً
$json_string = json_encode($data);
$decoded = json_decode($json_string, true); // true -> مصفوفة
// التحقق من صحة JSON
if (json_last_error() === JSON_ERROR_NONE) {
print_r($decoded);
} else {
echo "خطأ في JSON: " . json_last_error_msg();
}
?>
✅ معالجة JSON بشكل احترافي
php
<?php
class JsonHandler {
private static $errors = [
JSON_ERROR_NONE => 'لا يوجد خطأ',
JSON_ERROR_DEPTH => 'الحد الأقصى للعمق تم تجاوزه',
JSON_ERROR_STATE_MISMATCH => 'عدم تطابق في الحالة',
JSON_ERROR_CTRL_CHAR => 'حرف تحكم غير متوقع',
JSON_ERROR_SYNTAX => 'خطأ في بناء الجملة',
JSON_ERROR_UTF8 => 'ترميز UTF-8 غير صحيح',
JSON_ERROR_RECURSION => 'تكرار لا نهائي',
JSON_ERROR_INF_OR_NAN => 'قيمة INF أو NAN غير مسموحة',
JSON_ERROR_UNSUPPORTED_TYPE => 'نوع غير مدعوم'
];
public static function encode($data, $options = 0) {
$json = json_encode($data, $options);
if (json_last_error() !== JSON_ERROR_NONE) {
$error = self::$errors[json_last_error()] ?? 'خطأ غير معروف';
throw new Exception("فشل ترميز JSON: $error");
}
return $json;
}
public static function decode($json, $assoc = true) {
$data = json_decode($json, $assoc);
if (json_last_error() !== JSON_ERROR_NONE) {
$error = self::$errors[json_last_error()] ?? 'خطأ غير معروف';
throw new Exception("فشل فك ترميز JSON: $error");
}
return $data;
}
public static function validate($json) {
json_decode($json);
return json_last_error() === JSON_ERROR_NONE;
}
}
// استخدام الكلاس
try {
$data = ['name' => 'Ahmed', 'age' => 30];
$json = JsonHandler::encode($data, JSON_PRETTY_PRINT);
echo $json;
$decoded = JsonHandler::decode($json);
print_r($decoded);
// التحقق من الصلاحية
if (JsonHandler::validate('{"name":"Ahmed"}')) {
echo "JSON صحيح";
}
} catch (Exception $e) {
echo "خطأ: " . $e->getMessage();
}
?>
📌 14. أخطاء الـ API والـ HTTP Requests
✅ خطأ: file_get_contents(): Failed to open stream
php
// ❌ الكود الخاطئ
<?php
$response = file_get_contents('https://api.example.com/data');
echo $response;
?>
php
// ✅ الحل الصحيح - الطريقة الأولى (cURL)
<?php
function apiRequest($url, $method = 'GET', $data = null, $headers = []) {
$ch = curl_init();
// إعدادات cURL
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // للإنتاج استخدم true
// إعداد الـ headers
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
// إعداد الـ method والبيانات
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
} elseif ($method === 'PUT') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
} elseif ($method === 'DELETE') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("cURL Error: $error");
}
if ($httpCode >= 400) {
throw new Exception("HTTP Error: $httpCode - $response");
}
return json_decode($response, true);
}
// استخدام الدالة
try {
$result = apiRequest('https://api.example.com/users', 'GET', null, [
'Authorization: Bearer your_token',
'Content-Type: application/json'
]);
print_r($result);
} catch (Exception $e) {
error_log($e->getMessage());
echo "فشل الاتصال بالـ API";
}
?>
php
// ✅ الحل الصحيح - الطريقة الثانية (Guzzle HTTP Client)
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
class ApiClient {
private $client;
public function __construct($baseUrl, $timeout = 30) {
$this->client = new Client([
'base_uri' => $baseUrl,
'timeout' => $timeout,
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json'
]
]);
}
public function get($endpoint, $params = []) {
try {
$response = $this->client->get($endpoint, [
'query' => $params
]);
return json_decode($response->getBody(), true);
} catch (GuzzleException $e) {
$this->handleError($e);
}
}
public function post($endpoint, $data = []) {
try {
$response = $this->client->post($endpoint, [
'json' => $data
]);
return json_decode($response->getBody(), true);
} catch (GuzzleException $e) {
$this->handleError($e);
}
}
private function handleError($e) {
$statusCode = $e->getCode();
$message = $e->getMessage();
// معالجة أنواع مختلفة من الأخطاء
if ($e->hasResponse()) {
$body = $e->getResponse()->getBody()->getContents();
error_log("API Error: $statusCode - $body");
}
throw new Exception("فشل طلب الـ API: $message");
}
}
// استخدام الكلاس
$api = new ApiClient('https://api.example.com');
try {
$users = $api->get('/users', ['page' => 1, 'limit' => 10]);
print_r($users);
$newUser = $api->post('/users', [
'name' => 'Ahmed',
'email' => 'ahmed@email.com'
]);
} catch (Exception $e) {
echo "حدث خطأ: " . $e->getMessage();
}
?>
📌 15. أخطاء التشفير والتوقيع
✅ خطأ: hash_equals(): Expected known_string to be a string
php
// ❌ الكود الخاطئ - مقارنة غير آمنة
<?php
$password = '123456';
$hash = '$2y$10$encrypted_hash_here';
if ($password == $hash) { // غير آمن! لا تستخدم == مع التشفير
echo "كلمة المرور صحيحة";
}
?>
php
// ✅ الحل الصحيح - التشفير الآمن
<?php
class PasswordHandler {
// تشفير كلمة المرور
public static function hash($password) {
$options = [
'cost' => 12, // يوصى بـ 10-12
'salt' => random_bytes(22) // ملح عشوائي
];
return password_hash($password, PASSWORD_BCRYPT, $options);
}
// التحقق من كلمة المرور
public static function verify($password, $hash) {
if (!is_string($password) || !is_string($hash)) {
throw new InvalidArgumentException('يجب أن تكون المدخلات نصية');
}
return password_verify($password, $hash);
}
// التحقق من قوة كلمة المرور
public static function isStrong($password) {
return strlen($password) >= 8 &&
preg_match('/[A-Z]/', $password) &&
preg_match('/[a-z]/', $password) &&
preg_match('/[0-9]/', $password) &&
preg_match('/[^A-Za-z0-9]/', $password);
}
// توليد كلمة مرور عشوائية قوية
public static function generate($length = 12) {
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()';
$password = '';
for ($i = 0; $i < $length; $i++) {
$password .= $chars[random_int(0, strlen($chars) - 1)];
}
return $password;
}
}
// استخدام الكلاس
try {
// تشفير كلمة المرور
$password = 'MySecurePass123!';
$hash = PasswordHandler::hash($password);
echo "التشفير: $hash\n";
// التحقق من كلمة المرور
if (PasswordHandler::verify('MySecurePass123!', $hash)) {
echo "كلمة المرور صحيحة ✅\n";
} else {
echo "كلمة المرور خاطئة ❌\n";
}
// التحقق من قوة كلمة المرور
if (PasswordHandler::isStrong($password)) {
echo "كلمة المرور قوية 💪\n";
}
// توليد كلمة مرور جديدة
$newPass = PasswordHandler::generate(16);
echo "كلمة مرور جديدة: $newPass\n";
} catch (Exception $e) {
echo "خطأ: " . $e->getMessage();
}
?>
✅ تشفير البيانات (Encryption)
php
<?php
class EncryptionHandler {
private static $method = 'AES-256-CBC';
private static $key;
public static function init($key = null) {
if ($key === null) {
$key = $_ENV['ENCRYPTION_KEY'] ?? getenv('ENCRYPTION_KEY');
}
if (!$key) {
// توليد مفتاح جديد (احفظه في مكان آمن)
$key = bin2hex(openssl_random_pseudo_bytes(32));
throw new Exception("قم بحفظ هذا المفتاح: $key");
}
// التأكد من طول المفتاح المناسب
self::$key = hash('sha256', $key, true);
}
public static function encrypt($data) {
if (empty(self::$key)) {
self::init();
}
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(self::$method));
$encrypted = openssl_encrypt($data, self::$method, self::$key, 0, $iv);
// دمج الـ IV مع البيانات المشفرة
return base64_encode($iv . $encrypted);
}
public static function decrypt($encryptedData) {
if (empty(self::$key)) {
self::init();
}
$data = base64_decode($encryptedData);
$ivLength = openssl_cipher_iv_length(self::$method);
$iv = substr($data, 0, $ivLength);
$encrypted = substr($data, $ivLength);
return openssl_decrypt($encrypted, self::$method, self::$key, 0, $iv);
}
}
// استخدام التشفير
try {
EncryptionHandler::init('your-secret-key-here');
$original = 'بيانات حساسة جداً';
$encrypted = EncryptionHandler::encrypt($original);
echo "مشفر: $encrypted\n";
$decrypted = EncryptionHandler::decrypt($encrypted);
echo "مفكوك: $decrypted\n";
} catch (Exception $e) {
echo "خطأ تشفير: " . $e->getMessage();
}
?>
📌 16. أخطاء إدارة الذاكرة
✅ خطأ: Allowed memory size exhausted
php
// ❌ الكود الخاطئ - استهلاك كبير للذاكرة
<?php
// قراءة ملف كبير كامل في الذاكرة
$file = file_get_contents('huge_file.csv');
$data = explode("\n", $file); // تخزين كل البيانات في الذاكرة
?>
php
// ✅ الحل الصحيح - استخدام Streams
<?php
function processLargeFile($filename, $callback) {
$handle = fopen($filename, 'r');
if (!$handle) {
throw new Exception("لا يمكن فتح الملف: $filename");
}
$rowCount = 0;
while (($row = fgetcsv($handle)) !== false) {
$rowCount++;
// معالجة كل صف على حدة
$callback($row, $rowCount);
// تحرير الذاكرة بشكل دوري
if ($rowCount % 1000 == 0) {
gc_collect_cycles(); // جمع القمامة
memory_get_usage(); // يمكن تسجيل استخدام الذاكرة
}
}
fclose($handle);
return $rowCount;
}
// استخدام الدالة
$totalRows = processLargeFile('huge_file.csv', function($row, $index) {
// معالجة كل صف
if ($index % 1000 == 0) {
echo "معالجة الصف $index...\n";
}
});
echo "تم معالجة $totalRows صفوف\n";
?>
✅ إدارة الذاكرة المتقدمة
php
<?php
class MemoryManager {
private static $memoryLimit = null;
private static $peakMemory = 0;
public static function setMemoryLimit($limit) {
self::$memoryLimit = $limit;
ini_set('memory_limit', $limit);
}
public static function getMemoryUsage() {
return [
'current' => memory_get_usage(true),
'peak' => memory_get_peak_usage(true),
'real_usage' => memory_get_usage(false)
];
}
public static function optimize() {
// تحرير الذاكرة
gc_collect_cycles();
// إعادة تعيين الـ memory limit إذا لزم الأمر
if (memory_get_usage(true) > self::$peakMemory) {
self::$peakMemory = memory_get_usage(true);
}
}
public static function memoryToString($bytes) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
public static function logMemoryUsage($label = '') {
$usage = self::getMemoryUsage();
$log = sprintf(
"%s - Current: %s, Peak: %s, Limit: %s\n",
$label,
self::memoryToString($usage['current']),
self::memoryToString($usage['peak']),
ini_get('memory_limit')
);
error_log($log);
return $log;
}
public static function monitor($callback) {
$startTime = microtime(true);
$startMemory = memory_get_usage(true);
try {
$result = $callback();
} finally {
$endTime = microtime(true);
$endMemory = memory_get_usage(true);
$timeMs = round(($endTime - $startTime) * 1000, 2);
$memoryDiff = $endMemory - $startMemory;
$log = sprintf(
"Execution: %sms, Memory: %s (Δ%s)",
$timeMs,
self::memoryToString($endMemory),
self::memoryToString($memoryDiff)
);
error_log($log);
}
return $result;
}
}
// استخدام مدير الذاكرة
MemoryManager::setMemoryLimit('512M');
// تتبع استخدام الذاكرة
MemoryManager::logMemoryUsage('بداية التنفيذ');
// مراقبة أداء عملية
$result = MemoryManager::monitor(function() {
// عملية ثقيلة
$array = [];
for ($i = 0; $i < 100000; $i++) {
$array[] = "Item $i";
if ($i % 10000 == 0) {
MemoryManager::optimize();
}
}
return count($array);
});
echo "النتيجة: $result\n";
MemoryManager::logMemoryUsage('نهاية التنفيذ');
?>
📌 17. أخطاء التزامن (Concurrency)
✅ مشكلة Race Condition
php
// ❌ الكود الخاطئ
<?php
function updateCounter() {
$file = 'counter.txt';
$count = (int) file_get_contents($file);
$count++;
file_put_contents($file, $count); // قد يفقد تحديثات متزامنة
}
?>
php
// ✅ الحل الصحيح - استخدام الأقفال (File Locking)
<?php
function updateCounterSafe() {
$file = 'counter.txt';
$fp = fopen($file, 'c+');
if (flock($fp, LOCK_EX)) { // قفل حصري
$count = (int) fread($fp, filesize($file));
$count++;
fseek($fp, 0);
ftruncate($fp, 0);
fwrite($fp, (string) $count);
fflush($fp);
flock($fp, LOCK_UN); // فتح القفل
} else {
throw new Exception("لا يمكن الحصول على القفل");
}
fclose($fp);
return $count;
}
?>
✅ استخدام قاعدة البيانات للعمليات الذرية
php
<?php
class AtomicCounter {
private $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
$this->createTable();
}
private function createTable() {
$this->pdo->exec("
CREATE TABLE IF NOT EXISTS counters (
id VARCHAR(50) PRIMARY KEY,
value INT DEFAULT 0,
version INT DEFAULT 0
)
");
}
public function increment($id, $amount = 1) {
// عملية ذرية باستخدام قاعدة البيانات
$stmt = $this->pdo->prepare("
UPDATE counters
SET value = value + :amount, version = version + 1
WHERE id = :id
");
return $stmt->execute([
':id' => $id,
':amount' => $amount
]);
}
public function getValue($id) {
$stmt = $this->pdo->prepare("SELECT value FROM counters WHERE id = :id");
$stmt->execute([':id' => $id]);
return (int) $stmt->fetchColumn();
}
// عملية آمنة مع التحقق من الإصدار (Optimistic Locking)
public function updateWithVersion($id, $newValue) {
$this->pdo->beginTransaction();
try {
// قراءة القيمة الحالية مع الإصدار
$stmt = $this->pdo->prepare("
SELECT value, version FROM counters WHERE id = :id FOR UPDATE
");
$stmt->execute([':id' => $id]);
$current = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$current) {
throw new Exception("المفتاح غير موجود");
}
// تحديث القيمة
$stmt = $this->pdo->prepare("
UPDATE counters
SET value = :value, version = version + 1
WHERE id = :id AND version = :version
");
$result = $stmt->execute([
':id' => $id,
':value' => $newValue,
':version' => $current['version']
]);
if ($stmt->rowCount() === 0) {
throw new Exception("تم تعديل البيانات أثناء المعالجة");
}
$this->pdo->commit();
return true;
} catch (Exception $e) {
$this->pdo->rollBack();
throw $e;
}
}
}
// استخدام الكلاس
try {
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$counter = new AtomicCounter($pdo);
// زيادة آمنة
$counter->increment('visits', 1);
$counter->increment('visits', 1);
$counter->increment('visits', 1);
echo "الزيارات: " . $counter->getValue('visits') . "\n";
// تحديث مع التحقق من الإصدار
$counter->updateWithVersion('visits', 100);
} catch (Exception $e) {
echo "خطأ: " . $e->getMessage();
}
?>
📌 18. أخطاء معالجة الملفات الكبيرة
✅ قراءة ملفات CSV كبيرة
php
<?php
class LargeFileProcessor {
private $filePath;
private $batchSize = 1000;
private $callbacks = [];
public function __construct($filePath) {
if (!file_exists($filePath)) {
throw new Exception("الملف غير موجود: $filePath");
}
$this->filePath = $filePath;
}
public function setBatchSize($size) {
$this->batchSize = $size;
return $this;
}
public function onRow($callback) {
$this->callbacks['row'][] = $callback;
return $this;
}
public function onBatch($callback) {
$this->callbacks['batch'][] = $callback;
return $this;
}
public function onComplete($callback) {
$this->callbacks['complete'][] = $callback;
return $this;
}
public function processCSV($delimiter = ',', $hasHeader = true) {
$handle = fopen($this->filePath, 'r');
if (!$handle) {
throw new Exception("لا يمكن فتح الملف");
}
$headers = [];
$batch = [];
$rowCount = 0;
$batchCount = 0;
// قراءة الـ header إذا وجد
if ($hasHeader) {
$headers = fgetcsv($handle, 0, $delimiter);
}
while (($row = fgetcsv($handle, 0, $delimiter)) !== false) {
$rowCount++;
// دمج البيانات مع الـ headers
if ($hasHeader && count($headers) === count($row)) {
$row = array_combine($headers, $row);
}
// تنفيذ callbacks لكل صف
foreach ($this->callbacks['row'] ?? [] as $callback) {
$callback($row, $rowCount);
}
$batch[] = $row;
// معالجة الدفعة
if (count($batch) >= $this->batchSize) {
$batchCount++;
foreach ($this->callbacks['batch'] ?? [] as $callback) {
$callback($batch, $batchCount);
}
$batch = [];
// تحرير الذاكرة
gc_collect_cycles();
}
}
// معالجة الدفعة الأخيرة
if (!empty($batch)) {
$batchCount++;
foreach ($this->callbacks['batch'] ?? [] as $callback) {
$callback($batch, $batchCount);
}
}
fclose($handle);
// تنفيذ callbacks الاكتمال
foreach ($this->callbacks['complete'] ?? [] as $callback) {
$callback($rowCount, $batchCount);
}
return $rowCount;
}
}
// استخدام المعالج
$processor = new LargeFileProcessor('data.csv');
$processor->setBatchSize(5000)
->onRow(function($row, $index) {
// معالجة كل صف
if ($index % 10000 == 0) {
echo "معالجة الصف $index...\n";
}
})
->onBatch(function($batch, $batchNumber) {
// معالجة الدفعة (مثل حفظ في قاعدة البيانات)
echo "معالجة الدفعة $batchNumber (تم معالجة " . count($batch) . " صف)\n";
// مثال: حفظ في قاعدة البيانات
// $db->insertBatch($batch);
})
->onComplete(function($totalRows, $totalBatches) {
echo "تم الانتهاء! تم معالجة $totalRows صف في $totalBatches دفعة\n";
});
$processor->processCSV(',', true);
?>
📌 19. أخطاء تحسين استعلامات قاعدة البيانات
✅ مشكلة استعلامات N+1
php
// ❌ الكود الخاطئ - مشكلة N+1
<?php
// استعلام واحد للمستخدمين
$users = $db->query("SELECT * FROM users LIMIT 10");
foreach ($users as $user) {
// استعلام إضافي لكل مستخدم - هذه هي المشكلة!
$orders = $db->query("SELECT * FROM orders WHERE user_id = {$user['id']}");
// معالجة الطلبات...
}
?>
php
// ✅ الحل الصحيح - استخدام JOIN
<?php
// استعلام واحد مع JOIN
$sql = "
SELECT u.*, o.id as order_id, o.total, o.status
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
ORDER BY u.id, o.created_at DESC
";
$results = $db->query($sql);
// تجميع البيانات
$users = [];
while ($row = $results->fetch_assoc()) {
$userId = $row['id'];
if (!isset($users[$userId])) {
$users[$userId] = [
'id' => $row['id'],
'name' => $row['name'],
'email' => $row['email'],
'orders' => []
];
}
if ($row['order_id']) {
$users[$userId]['orders'][] = [
'id' => $row['order_id'],
'total' => $row['total'],
'status' => $row['status']
];
}
}
?>
✅ استخدام الفهارس (Indexes)
sql
-- ❌ استعلام بطيء بدون فهرسة SELECT * FROM orders WHERE user_id = 123 AND created_at > '2024-01-01'; -- ✅ إضافة فهارس مناسبة CREATE INDEX idx_orders_user_created ON orders (user_id, created_at); CREATE INDEX idx_orders_status ON orders (status); -- ✅ استعلام محسّن SELECT * FROM orders WHERE user_id = 123 AND created_at > '2024-01-01' ORDER BY created_at DESC LIMIT 10;
✅ استخدام التخزين المؤقت (Caching)
php
<?php
class QueryCache {
private $cache = [];
private $cacheTime = 3600; // ساعة واحدة
private $enabled = true;
public function __construct($enabled = true) {
$this->enabled = $enabled;
if ($this->enabled) {
// استخدام APC, Redis, أو Memcached
if (extension_loaded('apcu')) {
$this->cache = new APCuCache();
} elseif (extension_loaded('redis')) {
$this->cache = new RedisCache();
} else {
$this->cache = new ArrayCache();
}
}
}
public function get($query, $params = []) {
if (!$this->enabled) {
return null;
}
$key = $this->generateKey($query, $params);
return $this->cache->get($key);
}
public function set($query, $params, $result) {
if (!$this->enabled) {
return false;
}
$key = $this->generateKey($query, $params);
return $this->cache->set($key, $result, $this->cacheTime);
}
public function invalidate($query = null) {
if ($query) {
// حذف مفتاح محدد
$key = $this->generateKey($query, []);
$this->cache->delete($key);
} else {
// حذف كل الكاش
$this->cache->clear();
}
}
private function generateKey($query, $params) {
return 'query_' . md5($query . serialize($params));
}
}
class DBWithCache {
private $db;
private $cache;
public function __construct($db, $cache) {
$this->db = $db;
$this->cache = $cache;
}
public function query($sql, $params = [], $useCache = true) {
if (!$useCache) {
return $this->executeQuery($sql, $params);
}
// محاولة القراءة من الكاش
$cached = $this->cache->get($sql, $params);
if ($cached !== null) {
return $cached;
}
// تنفيذ الاستعلام
$result = $this->executeQuery($sql, $params);
// تخزين النتيجة في الكاش
$this->cache->set($sql, $params, $result);
return $result;
}
private function executeQuery($sql, $params) {
// تنفيذ الاستعلام هنا
// ...
}
}
?>
📌 20. أخطاء تعدد المهام (Multitasking)
✅ استخدام Parallel Processing في PHP
php
<?php
// ✅ استخدام pcntl_fork للعمليات المتوازية
class ParallelProcessor {
private $tasks = [];
private $maxProcesses = 4;
public function addTask($callback, $data) {
$this->tasks[] = [
'callback' => $callback,
'data' => $data,
'pid' => null,
'result' => null
];
return $this;
}
public function setMaxProcesses($count) {
$this->maxProcesses = $count;
return $this;
}
public function execute() {
if (!function_exists('pcntl_fork')) {
throw new Exception("pcntl_fork غير مدعوم في هذا النظام");
}
$running = [];
$results = [];
foreach ($this->tasks as $index => $task) {
// انتظار إذا وصلنا للحد الأقصى
while (count($running) >= $this->maxProcesses) {
$pid = pcntl_wait($status, WNOHANG);
if ($pid > 0) {
// إزالة العملية المنتهية
unset($running[$pid]);
}
usleep(100000); // 0.1 ثانية
}
$pid = pcntl_fork();
if ($pid == -1) {
throw new Exception("فشل إنشاء عملية جديدة");
} elseif ($pid == 0) {
// العملية الفرعية
$result = $task['callback']($task['data']);
exit($result);
} else {
// العملية الرئيسية
$this->tasks[$index]['pid'] = $pid;
$running[$pid] = $index;
}
}
// انتظار اكتمال جميع العمليات
while (count($running) > 0) {
$pid = pcntl_wait($status);
if ($pid > 0) {
$index = $running[$pid];
$this->tasks[$index]['result'] = pcntl_wexitstatus($status);
unset($running[$pid]);
}
}
// جمع النتائج
foreach ($this->tasks as $task) {
$results[] = $task['result'];
}
return $results;
}
}
// استخدام المعالج المتوازي
$processor = new ParallelProcessor();
$tasks = [
['name' => 'Task 1', 'data' => range(1, 100)],
['name' => 'Task 2', 'data' => range(1, 200)],
['name' => 'Task 3', 'data' => range(1, 300)],
['name' => 'Task 4', 'data' => range(1, 400)],
['name' => 'Task 5', 'data' => range(1, 500)]
];
foreach ($tasks as $task) {
$processor->addTask(
function($data) {
// معالجة البيانات
$sum = array_sum($data);
usleep(500000); // محاكاة عمل ثقيل
return $sum;
},
$task['data']
);
}
$processor->setMaxProcesses(3);
$results = $processor->execute();
echo "النتائج: " . implode(', ', $results) . "\n";
?>
📌 21. أخطاء Logging و Monitoring
✅ نظام تسجيل الأخطاء المتقدم
php
<?php
class AdvancedLogger {
const LEVEL_DEBUG = 0;
const LEVEL_INFO = 1;
const LEVEL_WARNING = 2;
const LEVEL_ERROR = 3;
const LEVEL_CRITICAL = 4;
private $logFile;
private $logLevel = self::LEVEL_INFO;
private $maxSize = 10485760; // 10MB
private $maxFiles = 5;
private $context = [];
private $handlers = [];
public function __construct($logFile = 'app.log') {
$this->logFile = $logFile;
$this->ensureLogDirectory();
}
public function setLevel($level) {
$this->logLevel = $level;
return $this;
}
public function addContext($key, $value) {
$this->context[$key] = $value;
return $this;
}
public function addHandler($handler) {
$this->handlers[] = $handler;
return $this;
}
public function debug($message, $data = null) {
$this->log(self::LEVEL_DEBUG, $message, $data);
}
public function info($message, $data = null) {
$this->log(self::LEVEL_INFO, $message, $data);
}
public function warning($message, $data = null) {
$this->log(self::LEVEL_WARNING, $message, $data);
}
public function error($message, $data = null) {
$this->log(self::LEVEL_ERROR, $message, $data);
}
public function critical($message, $data = null) {
$this->log(self::LEVEL_CRITICAL, $message, $data);
}
public function log($level, $message, $data = null) {
if ($level < $this->logLevel) {
return;
}
$logEntry = $this->formatLogEntry($level, $message, $data);
// كتابة في ملف السجلات
$this->writeLog($logEntry);
// تنفيذ معالجات إضافية
foreach ($this->handlers as $handler) {
$handler($logEntry, $level, $message, $data);
}
}
private function formatLogEntry($level, $message, $data) {
$levelNames = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'];
$timestamp = date('Y-m-d H:i:s.u');
$ip = $_SERVER['REMOTE_ADDR'] ?? 'CLI';
$method = $_SERVER['REQUEST_METHOD'] ?? 'CLI';
$uri = $_SERVER['REQUEST_URI'] ?? 'CLI';
$entry = [
'timestamp' => $timestamp,
'level' => $levelNames[$level],
'message' => $message,
'ip' => $ip,
'method' => $method,
'uri' => $uri,
'context' => $this->context
];
if ($data !== null) {
$entry['data'] = $data;
}
return json_encode($entry) . "\n";
}
private function writeLog($entry) {
// تدوير الملفات إذا لزم الأمر
$this->rotateLogs();
file_put_contents($this->logFile, $entry, FILE_APPEND | LOCK_EX);
}
private function rotateLogs() {
if (!file_exists($this->logFile)) {
return;
}
if (filesize($this->logFile) < $this->maxSize) {
return;
}
// حذف أقدم ملف
$lastFile = $this->logFile . '.' . $this->maxFiles;
if (file_exists($lastFile)) {
unlink($lastFile);
}
// إعادة تسمية الملفات
for ($i = $this->maxFiles - 1; $i > 0; $i--) {
$old = $this->logFile . '.' . $i;
$new = $this->logFile . '.' . ($i + 1);
if (file_exists($old)) {
rename($old, $new);
}
}
// نقل الملف الحالي
rename($this->logFile, $this->logFile . '.1');
}
private function ensureLogDirectory() {
$dir = dirname($this->logFile);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
}
// البحث في السجلات
public function search($search, $limit = 100) {
$results = [];
$handle = fopen($this->logFile, 'r');
if (!$handle) {
return $results;
}
while (($line = fgets($handle)) !== false && count($results) < $limit) {
$entry = json_decode($line, true);
if ($entry && strpos($line, $search) !== false) {
$results[] = $entry;
}
}
fclose($handle);
return $results;
}
}
// استخدام نظام التسجيل
$logger = new AdvancedLogger('logs/application.log');
$logger->setLevel(AdvancedLogger::LEVEL_DEBUG)
->addContext('app', 'MyApp')
->addContext('version', '1.0.0')
->addHandler(function($entry, $level, $message, $data) {
// إرسال الأخطاء الحرجة إلى البريد الإلكتروني
if ($level >= AdvancedLogger::LEVEL_CRITICAL) {
// mail('admin@example.com', 'خطأ حرج', $entry);
}
});
// تسجيل الأحداث
$logger->info('تطبيق بدأ');
$logger->debug('معالجة الطلب', ['user_id' => 123]);
$logger->warning('بطء في الاستعلام', ['query' => 'SELECT * FROM users', 'time' => 2.5]);
try {
// بعض الكود
throw new Exception('خطأ تجريبي');
} catch (Exception $e) {
$logger->error('خطأ في التطبيق', [
'exception' => [
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString()
]
]);
}
$logger->critical('خطأ فادح!', ['critical_data' => '...']);
// البحث في السجلات
$errors = $logger->search('ERROR');
echo "عدد الأخطاء: " . count($errors) . "\n";
?>
📌 22. أخطاء التعامل مع الصور والملفات
✅ معالجة الصور (تحويل، ضغط، تغيير الحجم)
php
<?php
class ImageProcessor {
private $sourcePath;
private $image;
private $type;
private $width;
private $height;
public function __construct($sourcePath) {
if (!file_exists($sourcePath)) {
throw new Exception("الملف غير موجود: $sourcePath");
}
$this->sourcePath = $sourcePath;
$this->loadImage();
}
private function loadImage() {
list($this->width, $this->height, $this->type) = getimagesize($this->sourcePath);
switch ($this->type) {
case IMAGETYPE_JPEG:
$this->image = imagecreatefromjpeg($this->sourcePath);
break;
case IMAGETYPE_PNG:
$this->image = imagecreatefrompng($this->sourcePath);
break;
case IMAGETYPE_GIF:
$this->image = imagecreatefromgif($this->sourcePath);
break;
default:
throw new Exception("نوع الصورة غير مدعوم");
}
if (!$this->image) {
throw new Exception("فشل تحميل الصورة");
}
}
public function resize($newWidth, $newHeight, $keepAspect = true) {
if ($keepAspect) {
$ratio = $this->width / $this->height;
if ($newWidth / $newHeight > $ratio) {
$newWidth = $newHeight * $ratio;
} else {
$newHeight = $newWidth / $ratio;
}
}
$newImage = imagecreatetruecolor($newWidth, $newHeight);
// الحفاظ على الشفافية للصور PNG و GIF
if ($this->type == IMAGETYPE_PNG || $this->type == IMAGETYPE_GIF) {
imagecolortransparent($newImage, imagecolorallocatealpha($newImage, 0, 0, 0, 127));
imagealphablending($newImage, false);
imagesavealpha($newImage, true);
}
imagecopyresampled(
$newImage, $this->image,
0, 0, 0, 0,
$newWidth, $newHeight,
$this->width, $this->height
);
$this->image = $newImage;
$this->width = $newWidth;
$this->height = $newHeight;
return $this;
}
public function crop($x, $y, $width, $height) {
$newImage = imagecrop($this->image, [
'x' => $x,
'y' => $y,
'width' => $width,
'height' => $height
]);
if ($newImage) {
$this->image = $newImage;
$this->width = $width;
$this->height = $height;
}
return $this;
}
public function addWatermark($watermarkPath, $position = 'bottom-right', $opacity = 50) {
$watermark = new self($watermarkPath);
// ضبط حجم العلامة المائية
$wmWidth = $this->width * 0.2;
$wmHeight = $watermark->height * ($wmWidth / $watermark->width);
$watermark->resize($wmWidth, $wmHeight, true);
// تحديد الموقع
$x = $this->width - $watermark->width - 10;
$y = $this->height - $watermark->height - 10;
switch ($position) {
case 'top-left':
$x = 10; $y = 10;
break;
case 'top-right':
$x = $this->width - $watermark->width - 10; $y = 10;
break;
case 'bottom-left':
$x = 10; $y = $this->height - $watermark->height - 10;
break;
case 'center':
$x = ($this->width - $watermark->width) / 2;
$y = ($this->height - $watermark->height) / 2;
break;
}
// دمج العلامة المائية مع الشفافية
imagecopymerge(
$this->image,
$watermark->image,
$x, $y, 0, 0,
$watermark->width,
$watermark->height,
$opacity
);
return $this;
}
public function compress($quality = 80) {
// ضغط الصورة دون تغيير الأبعاد
return $this;
}
public function save($outputPath, $quality = 80) {
$dir = dirname($outputPath);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
switch ($this->type) {
case IMAGETYPE_JPEG:
imagejpeg($this->image, $outputPath, $quality);
break;
case IMAGETYPE_PNG:
// PNG: التحويل من quality (0-100) إلى compression (0-9)
$compression = 9 - round($quality / 11.11);
imagepng($this->image, $outputPath, $compression);
break;
case IMAGETYPE_GIF:
imagegif($this->image, $outputPath);
break;
default:
throw new Exception("نوع الصورة غير مدعوم للحفظ");
}
return $this;
}
public function getInfo() {
return [
'width' => $this->width,
'height' => $this->height,
'type' => image_type_to_extension($this->type, false),
'size' => filesize($this->sourcePath)
];
}
public function __destruct() {
if ($this->image) {
imagedestroy($this->image);
}
}
}
// استخدام معالج الصور
try {
$image = new ImageProcessor('source.jpg');
// الحصول على معلومات الصورة
print_r($image->getInfo());
// تغيير الحجم مع الحفاظ على النسبة
$image->resize(800, 600, true)
->addWatermark('logo.png', 'bottom-right', 30)
->save('output/resized_with_watermark.jpg', 85);
echo "تم معالجة الصورة بنجاح ✅\n";
} catch (Exception $e) {
echo "خطأ في معالجة الصورة: " . $e->getMessage();
}
?>
🚀 نصائح إضافية لتحسين كود PHP
✅ استخدام الكود الأنظف (Clean Code)
php
<?php
// ❌ كود سيء
function do($d, $u) {
$r = [];
foreach($d as $k => $v) {
if($v['status'] == 'active' && $v['user_id'] == $u) {
$r[] = $v;
}
}
return $r;
}
// ✅ كود نظيف
class UserDataFilter {
private $data;
public function __construct(array $data) {
$this->data = $data;
}
public function filterByUserId(int $userId): array {
return array_filter($this->data, function($item) use ($userId) {
return $this->isUserActive($item) && $this->belongsToUser($item, $userId);
});
}
private function isUserActive(array $item): bool {
return isset($item['status']) && $item['status'] === 'active';
}
private function belongsToUser(array $item, int $userId): bool {
return isset($item['user_id']) && $item['user_id'] === $userId;
}
}
?>
✅ استخدام PHPStan أو Psalm لتحليل الكود
bash
# تثبيت PHPStan composer require --dev phpstan/phpstan # تحليل الكود vendor/bin/phpstan analyse src/ --level=max # تثبيت Psalm composer require --dev vimeo/psalm # تحليل الكود vendor/bin/psalm --init vendor/bin/psalm
✅ استخدام Xdebug للـ Debugging
ini
; php.ini [xdebug] zend_extension=xdebug.so xdebug.mode=debug xdebug.start_with_request=yes xdebug.client_port=9003 xdebug.client_host=127.0.0.1 xdebug.log=/var/log/xdebug.log xdebug.idekey=PHPSTORM
📊 جدول مقارنة: أدوات حل الأخطاء
| الأداة | الاستخدام | المزايا | العيوب |
|---|---|---|---|
| Xdebug | Debugging متقدم | • نقاط توقف • تتبع المكدس • تحليل الأداء | • بطيء • يحتاج تكوين |
| PHPStan | تحليل ثابت | • يكتشف الأخطاء مسبقاً • مستوى تحليل قابل للتعديل | • يحتاج تعلم • قد يعطي نتائج إيجابية خاطئة |
| Psalm | تحليل ثابت | • أسرع من PHPStan • تثبيت سهل | • أقل شهرة • دقة أقل في بعض الحالات |
| Error Logs | مراقبة مستمرة | • بسيط • لا يؤثر على الأداء | • لا يكتشف الأخطاء فوراً • يحتاج مراجعة يدوية |
| Sentry | مراقبة الأخطاء | • تنبيهات فورية • تقارير مفصلة • تحليل الاتجاهات | • مدفوع • يحتاج اتصال بالإنترنت |
🎯 هل تحتاج حل لمشكلة محددة؟
أرسل لي:
- الكود الكامل
- رسالة الخطأ مع الـ Stack Trace
- إصدار PHP والبيئة
سأعطيك حلاً مفصلاً ومخصصاً! 🚀
التفاصيل الكاملة، وسأقدم لك حلاً مخصصاً خطوة بخطوة! 🚀
مرحباً! من خلال خبرتي في حل مشكلات PHP، سأقوم بتحليل خطأ 500 Internal Server Error الخاص بك بشكل شامل وحلّه خطوة بخطوة.
📌 تحليل الخطأ
الخطأ الذي ظهر لك هو:
text
Oops! An Error Occurred The server returned a "500 Internal Server Error".
هذا خطأ عام في الخادم، وهو شائع جداً في تطبيقات PHP و Laravel تحديداً.
🔍 الأسباب الأكثر احتمالاً في بيئة Laravel
بناءً على تجربتي، أسباب هذا الخطأ في Laravel غالباً ما تكون:
- مشكلة في ملف
.env(تكوين قاعدة البيانات أو المفاتيح) - صلاحيات المجلدات (storage و bootstrap/cache)
- خطأ في الكود (خاصة في routes أو controllers)
- مشكلة في قاعدة البيانات (اتصال فاشل)
- نقص في الذاكرة أو وقت التنفيذ
🛠 الحلول التفصيلية (خطوة بخطوة)
✅ الحل الأول: تفعير عرض الأخطاء في Laravel
افتح ملف .env وغير:
env
APP_DEBUG=true APP_ENV=local
ثم تأكد من وجود هذا الكود في ملف config/app.php:
php
'debug' => env('APP_DEBUG', true),
✅ الحل الثاني: فحص سجل الأخطاء (الأهم!)
شغّل هذا الأمر في الطرفية لرؤية الخطأ الفعلي:
bash
tail -f storage/logs/laravel.log
أو ابحث في مجلد storage/logs/ عن ملف laravel.log واقرأ آخر الأخطاء.
مثال على خطأ شائع في السجل:
text
SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES)
هذا يعني أن بيانات الاتصال بقاعدة البيانات خاطئة.
✅ الحل الثالث: إصلاح صلاحيات المجلدات (الحل الأكثر شيوعاً!)
نفذ الأوامر التالية في مجلد المشروع:
bash
# للـ Linux/Mac chmod -R 775 storage chmod -R 775 bootstrap/cache chmod -R 775 vendor # أو sudo chmod -R 777 storage sudo chmod -R 777 bootstrap/cache
للـ Windows: اذهب إلى خصائص المجلدات وأعطي صلاحيات كاملة للمستخدم IIS_IUSRS أو Everyone.
✅ الحل الرابع: إعادة تعيين الكاش والتكوين
نفذ الأوامر التالية بالترتيب:
bash
# حذف الكاش php artisan cache:clear php artisan config:clear php artisan route:clear php artisan view:clear # إعادة بناء الكاش php artisan config:cache php artisan route:cache php artisan view:cache # أو بشكل شامل php artisan optimize
✅ الحل الخامس: التحقق من قاعدة البيانات
تأكد من صحة بيانات الاتصال في ملف .env:
env
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=your_database_name DB_USERNAME=your_username DB_PASSWORD=your_password
ثم جرب الاتصال:
bash
php artisan db:show
إذا فشل، تأكد من تشغيل خدمة MySQL أو استخدم SQLite:
env
DB_CONNECTION=sqlite # ثم أنشئ ملف database/database.sqlite
✅ الحل السادس: زيادة حدود PHP
أضف في ملف .htaccess (إن وجد):
apache
php_value memory_limit 256M php_value max_execution_time 300
أو في ملف php.ini:
ini
memory_limit = 256M max_execution_time = 300
✅ الحل السابع: فحص ملفات التوجيه (routes)
تأكد من صحة ملفات routes/web.php و routes/api.php. مثال على خطأ شائع:
php
// ❌ خطأ: نسيان إرجاع Response
Route::get('/test', function () {
// مفقود return
});
// ✅ صحيح
Route::get('/test', function () {
return view('welcome');
});
✅ الحل الثامن: إعادة تثبيت الاعتماديات
في بعض الأحيان، تتلف حزمة معينة:
bash
# حذف مجلد vendor rm -rf vendor # إعادة تثبيت الاعتماديات composer install # أو مع محاولة التحديث composer update
✅ الحل التاسع: استخدام Tinker للكشف السريع
جرب تشغيل هذا الأمر:
bash
php artisan tinker
ثم اختبر أي كود، مثل:
php
>>> config('app.env');
>>> DB::connection()->getPdo();
إذا ظهر خطأ هنا، فالمشكلة في البيئة أو قاعدة البيانات.
📋 قائمة المراجعة السريعة للـ Laravel
| الخطوة | الأمر/الإجراء | النتيجة المتوقعة |
|---|---|---|
| 1 | php artisan config:clear | مسح الكاش |
| 2 | php artisan cache:clear | مسح الكاش |
| 3 | chmod -R 775 storage bootstrap/cache | صلاحيات صحيحة |
| 4 | composer dump-autoload | إعادة تحميل الكلاسات |
| 5 | php artisan optimize | تحسين الأداء |
| 6 | التحقق من .env | بيانات صحيحة |
| 7 | php artisan serve | تشغيل السيرفر المحلي |
| 8 | فتح http://localhost:8000 | رؤية التطبيق |
🔧 حل متقدم: تشغيل السيرفر مع عرض الأخطاء
إذا لم تنجح أي من الحلول السابقة، جرب تشغيل السيرفر بهذه الطريقة لرؤية الخطأ مباشرة:
bash
php -S localhost:8000 -t public
ثم اذهب إلى المتصفح وافتح http://localhost:8000، وستظهر لك رسالة الخطأ الفعلية.
💡 نصائح إضافية للمستقبل
- استخدم Git للتحكم في الإصدارات، واحتفظ بنسخة احتياطية قبل أي تغيير.
- لا تهمل ملف
laravel.log، فهو أفضل صديق لك في حل الأخطاء. - اختبر التطبيق محلياً قبل رفعه إلى الخادم.
- استخدم
dd()لتصحيح الأخطاء:
php
dd($variable); // سيوقف التنفيذ ويعرض قيمة المتغير
🎯 خلاصة الحل النهائي
- أولاً: فعّل
APP_DEBUG=trueفي.env - ثانياً: اقرأ ملف
storage/logs/laravel.log - ثالثاً: صلح المشكلة التي تظهر في السجل
- رابعاً: نظف الكاش (
php artisan config:clear) - خامساً: أعد تشغيل السيرفر
إذا أرسلت لي محتوى ملف laravel.log، سأعطيك حلاً دقيقاً 100% لمشكلتك المحددة! 🚀
بكل سرور! سأقدم لك دليلاً موسعاً وشاملاً عن أخطاء Laravel و PHP، مع حالات نادرة وحلول احترافية من واقع التجربة.
📚 الجزء الثاني: أخطاء Laravel المتقدمة وحلولها
🔥 1. خطأ: Target class [Controller] does not exist.
❌ الكود المسبب:
php
// routes/web.php
Route::get('/user', 'UserController@show'); // الطريقة القديمة
✅ الحلول:
الحل 1: استخدام الـ Namespace الكامل
php
use App\Http\Controllers\UserController;
Route::get('/user', [UserController::class, 'show']);
الحل 2: استخدام الـ String مع الـ Namespace
php
Route::get('/user', 'App\Http\Controllers\UserController@show');
الحل 3: التأكد من وجود الكلاس
bash
# تحقق من وجود الملف ls app/Http/Controllers/UserController.php # أنشئ الـ Controller إذا لم يكن موجوداً php artisan make:controller UserController
🔥 2. خطأ: SQLSTATE[42S02]: Base table or view not found
❌ الكود المسبب:
php
// Model
class User extends Model
{
protected $table = 'userss'; // خطأ إملائي
}
✅ الحلول:
الحل 1: تحديد اسم الجدول بشكل صحيح
php
class User extends Model
{
protected $table = 'users'; // الاسم الصحيح
}
الحل 2: استخدام التسمية الافتراضية (Plural)
php
// Laravel يتوقع جدول 'users' تلقائياً
class User extends Model
{
// لا حاجة لتحديد $table
}
الحل 3: إنشاء الجدول إذا كان مفقوداً
bash
# إنشاء ميجريشن php artisan make:migration create_users_table # تشغيل الميجريشن php artisan migrate
🔥 3. خطأ: Maximum execution time of 60 seconds exceeded
❌ الكود المسبب:
php
// عملية طويلة جداً
foreach (range(1, 1000000) as $i) {
// معالجة ثقيلة
processHeavyTask($i);
}
✅ الحلول المتقدمة:
الحل 1: زيادة وقت التنفيذ مؤقتاً
php
// في بداية الكود set_time_limit(300); // 5 دقائق // أو في ملف .htaccess php_value max_execution_time 300
الحل 2: استخدام الـ Queue (الأفضل)
php
// إنشاء Job
php artisan make:job ProcessLargeData
// في الـ Job
class ProcessLargeData implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
// معالجة البيانات هنا
foreach (range(1, 1000000) as $i) {
// معالجة
}
}
}
// تشغيل الـ Job
ProcessLargeData::dispatch();
الحل 3: تقسيم المهمة (Chunking)
php
// معالجة البيانات على دفعات
User::chunk(100, function ($users) {
foreach ($users as $user) {
// معالجة كل مستخدم
}
});
🔥 4. خطأ: The stream or file "/path/to/storage/logs/laravel.log" could not be opened: failed to open stream: Permission denied
✅ الحلول الأمنية:
الحل 1: تعيين الصلاحيات الصحيحة (الموصى به)
bash
# للـ Linux/Mac sudo chown -R $USER:www-data storage sudo chown -R $USER:www-data bootstrap/cache chmod -R 775 storage chmod -R 775 bootstrap/cache # أو إذا كنت تستخدم Nginx sudo chown -R www-data:www-data storage sudo chown -R www-data:www-data bootstrap/cache
الحل 2: استخدام ACL (Access Control Lists)
bash
# منح صلاحيات للمستخدم الحالي sudo setfacl -R -m u:www-data:rwx storage sudo setfacl -R -m u:www-data:rwx bootstrap/cache sudo setfacl -R -m u:$USER:rwx storage sudo setfacl -R -m u:$USER:rwx bootstrap/cache
الحل 3: تغيير مالك المجلدات في بيئة التطوير
bash
# فقط للتطوير المحلي! sudo chmod -R 777 storage sudo chmod -R 777 bootstrap/cache
🔥 5. خطأ: No application encryption key has been specified
✅ الحل:
bash
# إنشاء مفتاح التشفير php artisan key:generate # التحقق من وجود المفتاح في .env APP_KEY=base64:your_generated_key_here
🔥 6. خطأ: Call to undefined method Illuminate\Database\Query\Builder::whereHas()
❌ الكود المسبب:
php
// استخدام whereHas على Query Builder (خطأ)
$users = DB::table('users')
->whereHas('posts', function ($query) {
$query->where('active', 1);
})
->get();
✅ الحلول:
الحل 1: استخدام Eloquent
php
$users = User::whereHas('posts', function ($query) {
$query->where('active', 1);
})->get();
الحل 2: استخدام JOIN في Query Builder
php
$users = DB::table('users')
->join('posts', 'users.id', '=', 'posts.user_id')
->where('posts.active', 1)
->select('users.*')
->distinct()
->get();
الحل 3: استخدام whereExists
php
$users = DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('posts')
->whereColumn('posts.user_id', 'users.id')
->where('posts.active', 1);
})
->get();
🔥 7. خطأ: Method Illuminate\Http\Request::input does not exist
❌ الكود المسبب:
php
// استخدام input() على Request بطريقة خاطئة $request->input(); // بدون معامل
✅ الحلول:
الحل 1: استخدام input() مع معامل
php
$name = $request->input('name');
$all = $request->all(); // لجلب جميع البيانات
الحل 2: استخدام الـ Helper functions
php
$name = request('name');
$all = request()->all();
الحل 3: استخدام الـ Dependency Injection
php
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email',
]);
// أو
$name = $request->input('name');
}
🔥 8. خطأ: Class 'App\Models\User' not found
✅ الحلول:
الحل 1: التحقق من الـ Namespace
php
// تأكد من وجود هذا السطر في بداية الملف
namespace App\Models;
class User extends Authenticatable
{
// ...
}
الحل 2: إعادة تحميل الـ Autoloader
bash
composer dump-autoload
الحل 3: التحقق من اسم الملف
bash
# تأكد من أن اسم الملف مطابق لاسم الكلاس # User.php (وليس user.php) ls app/Models/User.php
🛠 أدوات متقدمة لتشخيص الأخطاء
1. Laravel Debugbar
التثبيت:
bash
composer require barryvdh/laravel-debugbar --dev
الاستخدام:
يعرض شريط أدوات في أسفل الصفحة يحتوي على:
- وقت التنفيذ
- استعلامات قاعدة البيانات
- الذاكرة المستخدمة
- الـ Routes
- المتغيرات
2. Telescope (لتتبع الأداء)
التثبيت:
bash
composer require laravel/telescope --dev php artisan telescope:install php artisan migrate
الاستخدام:
bash
php artisan telescope
يعرض:
- الطلبات الواردة
- الاستثناءات
- الاستعلامات البطيئة
- الـ Jobs
3. Ray (للتصحيح المتقدم)
التثبيت:
bash
composer require spatie/laravel-ray --dev
الاستخدام:
php
ray($variable)->green(); // عرض متغير بلون معين ray()->showQueries(); // عرض استعلامات DB ray()->caller(); // عرض موقع الاستدعاء
4. Log Viewer (لعرض السجلات)
التثبيت:
bash
composer require opcodesio/log-viewer --dev
الاستخدام:
bash
php artisan log-viewer:publish
ثم افتح /log-viewer في المتصفح.
🔐 أخطاء أمنية شائعة في Laravel
1. Mass Assignment Vulnerability
❌ الكود غير الآمن:
php
// في Controller
public function update(Request $request, $id)
{
$user = User::find($id);
$user->update($request->all()); // خطير!
}
✅ الحلول:
الحل 1: استخدام الـ $fillable
php
class User extends Model
{
protected $fillable = ['name', 'email', 'password'];
}
الحل 2: استخدام الـ $guarded
php
class User extends Model
{
protected $guarded = ['id', 'is_admin'];
}
الحل 3: استخدام Request مع validation
php
public function update(Request $request, $id)
{
$validated = $request->validate([
'name' => 'required|string',
'email' => 'required|email',
]);
$user = User::find($id);
$user->update($validated);
}
2. SQL Injection Prevention
❌ الكود غير الآمن:
php
// استخدام الـ Query Builder بدون prepared statements
$users = DB::select("SELECT * FROM users WHERE name = '$name'");
✅ الحلول الآمنة:
الحل 1: استخدام Query Builder
php
$users = DB::table('users')
->where('name', $name)
->get();
الحل 2: استخدام Eloquent
php
$users = User::where('name', $name)->get();
الحل 3: استخدام prepared statements يدوياً
php
$users = DB::select('SELECT * FROM users WHERE name = ?', [$name]);
📊 جدول مقارنة: حلول الأخطاء حسب نوع المشكلة
| المشكلة | الحل السريع | الحل المتقدم | الأدوات المطلوبة |
|---|---|---|---|
| الأذونات | chmod -R 775 storage | ACL + تعيين المالك الصحيح | Terminal |
| الكاش | php artisan config:clear | php artisan optimize | Artisan |
| قاعدة البيانات | التحقق من .env | استخدام DB::reconnect() | MySQL/PostgreSQL |
| الذاكرة | زيادة memory_limit | استخدام Chunking أو Queue | php.ini |
| الوقت | زيادة max_execution_time | استخدام Queue | php.ini |
| التوجيه | php artisan route:clear | استخدام Route Caching | Artisan |
🎯 خطة تشخيص متكاملة لأي خطأ في Laravel
الخطوة 1: تفعيل التصحيح
bash
# في ملف .env
APP_DEBUG=true
APP_ENV=local
# في config/app.php
'debug' => env('APP_DEBUG', true),
الخطوة 2: قراءة سجل الأخطاء
bash
# عرض آخر 50 سطراً tail -n 50 storage/logs/laravel.log # متابعة السجل مباشرة tail -f storage/logs/laravel.log
الخطوة 3: تنظيف الكاش
bash
php artisan config:clear php artisan cache:clear php artisan view:clear php artisan route:clear
الخطوة 4: إعادة تحميل الـ Autoloader
bash
composer dump-autoload
الخطوة 5: التحقق من قاعدة البيانات
bash
# اختبار الاتصال php artisan db:show # تشغيل الميجريشن php artisan migrate --pretend # لمعرفة ما سيحدث php artisan migrate # للتشغيل الفعلي
الخطوة 6: تشغيل السيرفر المحلي
bash
php artisan serve --host=0.0.0.0 --port=8000
💡 نصائح ذهبية لمطوري Laravel
1. استخدم dd() و dump() بحكمة
php
// عرض متغير وإيقاف التنفيذ dd($variable); // عرض متغير والاستمرار dump($variable); // عرض استعلامات قاعدة البيانات DB::enableQueryLog(); // ... تنفيذ استعلامات ... dd(DB::getQueryLog());
2. استخدم الـ Exception Handling المخصص
php
// app/Exceptions/Handler.php
public function render($request, Exception $exception)
{
if ($exception instanceof ModelNotFoundException) {
return response()->json([
'error' => 'Resource not found'
], 404);
}
return parent::render($request, $exception);
}
3. استخدم الـ Global Scopes للتصفية التلقائية
php
class ActiveScope implements GlobalScope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('is_active', true);
}
}
class User extends Model
{
protected static function booted()
{
static::addGlobalScope(new ActiveScope);
}
}
4. استخدم الـ Observers لمراقبة التغييرات
bash
php artisan make:observer UserObserver --model=User
php
class UserObserver
{
public function created(User $user)
{
Log::info('User created: ' . $user->email);
}
public function updated(User $user)
{
Log::info('User updated: ' . $user->email);
}
}
5. استخدم الـ API Resources لتنسيق الـ Responses
bash
php artisan make:resource UserResource
php
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at->toDateTimeString(),
];
}
}
📦 حلول لأخطاء الـ Packages
مشكلة: Class 'Package\Class' not found
✅ الحلول:
bash
# 1. تثبيت الـ package composer require vendor/package-name # 2. إعادة تحميل الـ autoloader composer dump-autoload # 3. نشر التهيئة (إذا لزم الأمر) php artisan vendor:publish --provider="Vendor\Package\PackageServiceProvider" # 4. تشغيل الميجريشن (إذا لزم الأمر) php artisan migrate
مشكلة: Package version conflict
✅ الحلول:
bash
# 1. معرفة الإصدارات المتاحة
composer show vendor/package-name --all
# 2. تثبيت إصدار محدد
composer require vendor/package-name:^1.0
# 3. تحديث جميع الـ packages
composer update
# 4. حل التعارضات يدوياً في composer.json
{
"require": {
"vendor/package1": "^1.0",
"vendor/package2": "^2.0"
}
}
🚀 أدوات مفيدة خارجية
1. Laravel Shift (لتحديث الإصدارات)
bash
# تحديث من Laravel 8 إلى 9 مثلاً # استخدم موقع shift.laravel.com
2. Laravel Dump Server (لعرض الـ Dumps)
bash
composer require --dev symfony/var-dumper # تشغيل السيرفر php artisan dump-server # الآن يمكنك استخدام dd() و dump() وستظهر هنا
3. Laravel IDE Helper (للـ Auto-completion)
bash
composer require --dev barryvdh/laravel-ide-helper php artisan ide-helper:generate php artisan ide-helper:models
📝 قائمة التحقق النهائية عند مواجهة أي خطأ
- □ هل
APP_DEBUGمضبوط علىtrue؟ - □ هل اطلعت على ملف
storage/logs/laravel.log؟ - □ هل البيانات في ملف
.envصحيحة؟ - □ هل صلاحيات المجلدات صحيحة (
storageوbootstrap/cache)؟ - □ هل قمت بتنظيف الكاش؟
- □ هل
composer dump-autoloadيعمل بشكل صحيح؟ - □ هل قاعدة البيانات تعمل وتستطيع الاتصال بها؟
- □ هل المتغيرات المطلوبة موجودة؟
- □ هل نسيت
returnفي الـ Controllers؟ - □ هل الـ Routes معرفة بشكل صحيح؟
- □ هل الـ Models تستخدم الـ Namespace الصحيح؟
🎓 خلاصة نهائية
تذكر دائماً في Laravel:
- الـ Logs هي صديقك الأول – اقرأها دائماً أولاً
- Artisan هو أداة قوية – استخدم الأوامر بانتظام
- الـ Community كبيرة – ابحث عن مشكلتك، غالباً حُلت مسبقاً
- التوثيق الرسمي هو المرجع – اقرأه دائماً
- اختبر على محلي قبل الرفع إلى الإنتاج
هل لديك خطأ محدد لم تحله بعد؟
أرسل لي:
- محتوى ملف
laravel.log - الكود المسبب للخطأ
- إصدار Laravel و PHP
- البيئة (Windows/Linux/Mac)
وسأعطيك حلاً مخصصاً 100%! 🚀
This response is AI-generated, for reference only.
بكل سرور! سأقدم لك من الحلول المتقدمة والنادرة لأخطاء Laravel و PHP، مع حالات من واقع التطبيقات الكبيرة وتقنيات احترافية.
🚀 الجزء الثالث: أخطاء متقدمة جداً وحلولها
🔥 9. خطأ: PHP Fatal error: Uncaught ReflectionException: Class config does not exist
❌ الكود المسبب:
php
// محاولة الوصول إلى config قبل تحميله
$value = config('app.timezone'); // قبل تهيئة Laravel
✅ الحلول المتقدمة:
الحل 1: استخدام الـ Helper بعد التهيئة
php
// في bootstrap/app.php أو في Service Provider
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
// الآن يمكن استخدام config
$timezone = config('app.timezone');
الحل 2: تحميل التكوين يدوياً
php
// إذا كنت في سكربت خارجي $config = require __DIR__.'/../config/app.php'; $timezone = $config['timezone'];
الحل 3: استخدام الـ Application Container
php
$app = require __DIR__.'/../bootstrap/app.php';
$timezone = $app['config']->get('app.timezone');
🔥 10. خطأ: PDOException: SQLSTATE[08006] [7] could not connect to server: Connection refused
✅ الحلول المتقدمة:
الحل 1: التحقق من خدمة قاعدة البيانات
bash
# Linux sudo systemctl status postgresql sudo systemctl start postgresql # Mac brew services list brew services start postgresql # Windows net start postgresql-13
الحل 2: استخدام الـ Connection Retry Logic
php
// في config/database.php
'retry' => [
'max_attempts' => 5,
'backoff' => 100, // milliseconds
],
// أو في الكود
$retries = 5;
while ($retries > 0) {
try {
$connection = DB::connection();
break;
} catch (PDOException $e) {
$retries--;
if ($retries === 0) throw $e;
sleep(1);
}
}
الحل 3: استخدام الـ Connection Pool
php
// config/database.php
'connections' => [
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
'sslmode' => 'prefer',
'options' => [
PDO::ATTR_PERSISTENT => true, // Persistent connection
],
],
],
🔥 11. خطأ: ErrorException: Trying to get property of non-object
❌ الكود المسبب:
php
// العلاقة غير محملة $user = User::find(1); echo $user->profile->bio; // خطأ إذا كان profile == null
✅ الحلول المتقدمة:
الحل 1: استخدام Optional Helper (Laravel 8+)
php
echo optional($user->profile)->bio ?? 'No bio';
الحل 2: استخدام Null Coalescing Operator
php
echo $user->profile?->bio ?? 'No bio'; // PHP 8+
الحل 3: استخدام Eager Loading مع Default
php
$user = User::with(['profile' => function($query) {
$query->select(['user_id', 'bio']);
}])->find(1);
echo $user->profile->bio ?? 'No bio';
الحل 4: استخدام Accessor
php
class User extends Model
{
public function getBioAttribute()
{
return $this->profile?->bio ?? 'No bio available';
}
}
// الاستخدام
echo $user->bio;
🔥 12. خطأ: League\Flysystem\UnableToWriteFile: Unable to write file at location: permission denied
✅ الحلول المتقدمة:
الحل 1: استخدام الـ Storage Facade مع Driver مناسب
php
// config/filesystems.php
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'throw' => true, // إلقاء استثناء عند الفشل
'permissions' => [
'file' => [
'public' => 0644,
'private' => 0600,
],
'dir' => [
'public' => 0755,
'private' => 0700,
],
],
],
],
الحل 2: استخدام الـ try-catch مع Retry
php
use League\Flysystem\UnableToWriteFile;
try {
Storage::disk('local')->put('file.txt', $content);
} catch (UnableToWriteFile $e) {
// محاولة إنشاء المجلد
Storage::disk('local')->makeDirectory('folder');
// المحاولة مرة أخرى
Storage::disk('local')->put('file.txt', $content);
}
الحل 3: استخدام الـ Temporary Disk
php
// كتابة في مجلد مؤقت
$tempFile = tempnam(sys_get_temp_dir(), 'laravel_');
file_put_contents($tempFile, $content);
// نقل الملف لاحقاً
Storage::disk('local')->put('final.txt', file_get_contents($tempFile));
unlink($tempFile);
🔥 13. خطأ: Illuminate\Contracts\Container\BindingResolutionException: Target class [view] does not exist
✅ الحلول:
الحل 1: استخدام الـ Facade
php
use Illuminate\Support\Facades\View;
return View::make('welcome', ['name' => 'Laravel']);
الحل 2: استخدام الـ Helper Function
php
return view('welcome', ['name' => 'Laravel']);
الحل 3: استخدام الـ Service Provider للتسجيل
php
// في AppServiceProvider
public function register()
{
$this->app->bind('view', function ($app) {
return new \Illuminate\View\Factory(
$app['view.engine.resolver'],
$app['view.finder'],
$app['events']
);
});
}
🔥 14. خطأ: LogicException: Please provide a valid cache path
✅ الحلول:
الحل 1: إنشاء المجلدات المفقودة
bash
# إنشاء مجلدات الـ Cache mkdir -p storage/framework/cache mkdir -p storage/framework/sessions mkdir -p storage/framework/views mkdir -p storage/framework/testing
الحل 2: تعيين صلاحيات صحيحة
bash
chmod -R 775 storage/framework chmod -R 775 storage/logs
الحل 3: التحقق من وجود المجلدات في الكود
php
// في AppServiceProvider
public function boot()
{
$cachePaths = [
storage_path('framework/cache'),
storage_path('framework/sessions'),
storage_path('framework/views'),
];
foreach ($cachePaths as $path) {
if (!is_dir($path)) {
mkdir($path, 0755, true);
}
}
}
🔥 15. خطأ: UnexpectedValueException: The stream or file could not be opened
✅ الحلول المتقدمة:
الحل 1: تعيين مسار مخصص للـ Logs
php
// في config/logging.php
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single', 'slack'],
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'permission' => 0644, // تعيين صلاحيات الملف
'locking' => true, // قفل الملف للكتابة المتزامنة
],
],
الحل 2: استخدام Channel مختلف لبيئات مختلفة
php
// .env
LOG_CHANNEL=daily
// config/logging.php
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => 7, // الاحتفاظ بآخر 7 أيام
'permission' => 0644,
],
الحل 3: استخدام الـ Syslog (للسيرفرات)
php
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
],
🛡 أخطاء الأداء وتحسينها
🔥 16. مشكلة: N+1 Query في الـ API
❌ الكود البطيء:
php
// Controller
$posts = Post::all();
foreach ($posts as $post) {
$post->author->name; // N+1 Query
}
✅ الحلول المتقدمة:
الحل 1: Eager Loading
php
$posts = Post::with('author')->get();
foreach ($posts as $post) {
echo $post->author->name; // استعلام واحد فقط
}
الحل 2: Lazy Eager Loading
php
$posts = Post::all();
if (request('with_author')) {
$posts->load('author');
}
الحل 3: استخدام الـ Resource مع Relations
php
class PostResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'author' => new UserResource($this->whenLoaded('author')),
];
}
}
// في Controller
return PostResource::collection(Post::with('author')->paginate());
🔥 17. مشكلة: Queries بطيئة جداً
✅ الحلول المتقدمة:
الحل 1: استخدام الـ Indexes
php
// إنشاء ميجريشن
Schema::table('posts', function (Blueprint $table) {
$table->index('created_at');
$table->index(['user_id', 'status']);
$table->fullText('content'); // لـ Full-Text Search
});
// في Model
class Post extends Model
{
protected $casts = [
'created_at' => 'datetime',
];
}
الحل 2: استخدام الـ Raw Queries للاستعلامات المعقدة
php
$users = DB::select("
SELECT u.*, COUNT(p.id) as posts_count
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
WHERE u.created_at >= ?
GROUP BY u.id
HAVING posts_count > 5
", [now()->subDays(30)]);
الحل 3: استخدام الـ Cache
php
use Illuminate\Support\Facades\Cache;
$users = Cache::remember('active_users', 3600, function () {
return User::withCount('posts')
->having('posts_count', '>', 5)
->get();
});
// أو باستخدام Tags
Cache::tags(['users', 'posts'])->remember('active_users', 3600, function () {
return User::withCount('posts')
->having('posts_count', '>', 5)
->get();
});
// حذف الكاش عند التحديث
Cache::tags(['users', 'posts'])->flush();
🔥 18. مشكلة: Session Lag أو فقدان البيانات
✅ الحلول المتقدمة:
الحل 1: استخدام Redis للـ Sessions
php
// config/session.php
'driver' => env('SESSION_DRIVER', 'redis'),
// .env
SESSION_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
الحل 2: استخدام الـ Database Sessions
bash
php artisan session:table php artisan migrate
php
// config/session.php
'driver' => env('SESSION_DRIVER', 'database'),
الحل 3: التحقق من Cookie Configuration
php
// config/session.php
'cookie' => env('SESSION_COOKIE', 'laravel_session'),
'path' => '/',
'domain' => env('SESSION_DOMAIN', null),
'secure' => env('SESSION_SECURE_COOKIE', false),
'http_only' => true,
'same_site' => 'lax', // أو 'strict'
🔐 أخطاء الأمان المتقدمة
🔥 19. CSRF Token Mismatch
✅ الحلول:
الحل 1: إضافة الـ Token في الـ Forms
php
<form method="POST" action="/profile">
@csrf
<!-- أو -->
{{ csrf_field() }}
</form>
الحل 2: إضافة الـ Token في Axios (لـ API)
javascript
axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').content;
// أو
axios.post('/api/data', data, {
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
});
الحل 3: استثناء Routes من CSRF (بحذر)
php
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
'webhook/*',
'api/webhook',
];
الحل 4: استخدام الـ API Tokens بدلاً من CSRF
php
// Sanctum
$user->createToken('token-name')->plainTextToken;
// في الطلبات
Authorization: Bearer {token}
🔥 20. XSS Protection
✅ الحلول المتقدمة:
الحل 1: استخدام Blade Auto-escaping
php
{{ $user->name }} // تلقائياً محمي
// لتجنب الإسكيب (بحذر شديد)
{!! $user->bio !!} // خطر
الحل 2: استخدام الـ Purifier (HTML Purifier)
bash
composer require mews/purifier
php
// config/purifier.php
return [
'settings' => [
'default' => [
'HTML.Doctype' => 'HTML 4.01 Transitional',
'HTML.Allowed' => 'p,b,i,u,a[href],img[src]',
'CSS.AllowedProperties' => [],
'AutoFormat.RemoveEmpty' => true,
],
],
];
// الاستخدام
$cleanHtml = Purifier::clean($request->input('content'));
الحل 3: استخدام Content Security Policy (CSP)
php
// في Middleware
public function handle($request, Closure $next)
{
$response = $next($request);
$response->header('Content-Security-Policy', "
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
");
return $response;
}
🧪 أخطاء الاختبارات (Testing)
🔥 21. خطأ: PHPUnit\Framework\Exception: Class 'Tests\TestCase' not found
✅ الحلول:
الحل 1: التحقق من الـ Namespace
php
// tests/Feature/UserTest.php namespace Tests\Feature; // صحيح use Tests\TestCase; // يجب أن يكون موجوداً
الحل 2: تشغيل الـ Autoloader
bash
composer dump-autoload
الحل 3: التحقق من إعدادات phpunit.xml
xml
<!-- phpunit.xml -->
<phpunit>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
</phpunit>
الحل 4: إنشاء ملف TestCase
bash
php artisan make:test TestCase
🔥 22. خطأ: Failed asserting that false is true في الاختبارات
✅ الحلول المتقدمة:
الحل 1: Debugging الاختبارات
php
public function testUserCreation()
{
$user = User::factory()->create([
'email' => 'test@example.com',
]);
$this->assertDatabaseHas('users', [
'email' => 'test@example.com',
]);
// لرؤية ما يحدث
dump($user->toArray());
// أو
Log::info('User created', $user->toArray());
}
الحل 2: استخدام الـ Exception Handling في الاختبارات
php
public function testUserDeletion()
{
$user = User::factory()->create();
$response = $this->actingAs($user)
->delete("/users/{$user->id}");
$response->assertStatus(302);
// التحقق من أن المستخدم حُذف
$this->assertDatabaseMissing('users', ['id' => $user->id]);
}
الحل 3: استخدام الـ Database Transactions
php
use Illuminate\Foundation\Testing\RefreshDatabase;
class UserTest extends TestCase
{
use RefreshDatabase;
public function test_user_can_be_created()
{
// Database سيتم إعادة تعيينها قبل كل اختبار
}
}
📦 أخطاء الـ Packages الشهيرة
🔥 23. مشكلة: Laravel Sanctum Authentication Issues
✅ الحلول:
الحل 1: نشر التهيئة بشكل صحيح
bash
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" php artisan migrate
الحل 2: إضافة Sanctum Middleware
php
// app/Http/Kernel.php
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
الحل 3: إعداد Cors بشكل صحيح
php
// config/cors.php
return [
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://localhost:3000'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true, // مهم!
];
🔥 24. مشكلة: Laravel Socialite
✅ الحلول:
الحل 1: نشر التهيئة
bash
composer require laravel/socialite php artisan vendor:publish --provider="Laravel\Socialite\SocialiteServiceProvider"
الحل 2: إعداد الـ Services
php
// config/services.php
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI'),
],
'facebook' => [
'client_id' => env('FACEBOOK_CLIENT_ID'),
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
'redirect' => env('FACEBOOK_REDIRECT_URI'),
],
الحل 3: معالجة الأخطاء
php
try {
$user = Socialite::driver('google')->user();
} catch (\Exception $e) {
Log::error('Socialite error: ' . $e->getMessage());
return redirect('/login')->withErrors(['email' => 'Authentication failed']);
}
🔧 أدوات متقدمة للـ Debugging
1. Laravel Horizon (للـ Queues)
bash
composer require laravel/horizon php artisan horizon:install php artisan migrate php artisan horizon
2. Laravel Nova Debug Bar
bash
composer require beyondcode/laravel-query-detector --dev
3. Clockwork (بديل Debugbar)
bash
composer require itsgoingd/clockwork php artisan vendor:publish --provider="Clockwork\Support\Laravel\ClockworkServiceProvider"
📊 جدول الأدوات حسب المشكلة
| المشكلة | الأداة المناسبة | كيف تساعد |
|---|---|---|
| استعلامات بطيئة | Debugbar / Telescope | تعرض وقت الاستعلام وعددها |
| أخطاء غير معروفة | Ray / dd() | تكشف قيمة المتغيرات |
| مشاكل الأداء | Blackfire / Xdebug | تحليل الأداء خطوة بخطوة |
| أخطاء API | Postman / Insomnia | اختبار الـ Endpoints |
| مشاكل Queue | Horizon | مراقبة الـ Jobs |
| أخطاء Database | Laravel Tinker | اختبار الاستعلامات مباشرة |
📝 خطة طوارئ للحالات الحرجة
عندما ينفد كل شيء:
bash
# 1. نسخ احتياطي للمشروع cp -r project project_backup_$(date +%Y%m%d) # 2. حذف كل الكاش php artisan optimize:clear rm -rf bootstrap/cache/* rm -rf storage/framework/cache/* # 3. إعادة تثبيت التبعيات rm -rf vendor composer install # 4. إعادة تعيين قاعدة البيانات (فقط للتطوير) php artisan migrate:fresh --seed # 5. إعادة تشغيل السيرفر php artisan serve
🎯 خلاصة نهائية متقدمة
القواعد الذهبية للمطور المحترف:
- اقرأ Stack Trace كاملاً – الحل موجود في أول سطرين
- استخدم Logs بحكمة – لا تكتب Logs عشوائياً
- استخدم Exceptions – لا تخف من إلقائها
- اختبر كل شيء – حتى الـ Code الذي لا تتوقع أن يفشل
- تعلم من الأخطاء – سجل كل خطأ وكيف حليته
- اطلب المساعدة – Laravel community كبيرة جداً
مثال على حل متكامل لخطأ معقد:
php
// معالج شامل للأخطاء
public function handleComplexOperation($data)
{
DB::beginTransaction();
try {
// التحقق من المدخلات
if (empty($data)) {
throw new InvalidArgumentException('Data cannot be empty');
}
// المعالجة
$result = $this->processData($data);
// التحقق من النتيجة
if (!$result) {
throw new RuntimeException('Processing failed');
}
DB::commit();
// تسجيل نجاح العملية
Log::info('Operation successful', ['data' => $data]);
return $result;
} catch (InvalidArgumentException $e) {
DB::rollBack();
Log::warning('Invalid input', ['error' => $e->getMessage()]);
throw $e;
} catch (RuntimeException $e) {
DB::rollBack();
Log::error('Processing failed', ['error' => $e->getMessage()]);
// محاولة التعافي
$fallback = $this->getFallbackData();
return $fallback;
} catch (\Exception $e) {
DB::rollBack();
Log::critical('Unexpected error', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
// إشعار المطور
$this->notifyDeveloper($e);
throw $e;
}
}
هل لديك مشكلة محددة لم تحلها بعد؟
أرسل لي:
- الكود كاملاً
- رسالة الخطأ كاملة
- محتوى
laravel.log - إصدارات PHP و Laravel
- البيئة (نظام التشغيل)
وسأعطيك حلاً مخصصاً ودقيقاً 100%! 🚀