chore: استيراد أولي من سيرو (ecfe7568) — بلا أي تعديل
نسخة كاملة من مستودع سيرو عند ecfe7568 لتكون أساس تطبيق «انطلق». نُسخ المتعقَّب في git فقط (12,509 ملفاً / 302 م.ب) بـ git archive، لا `cp -r` — فاستُثنيت تلقائياً مخلفات البناء (build · node_modules · .dart_tool · .gradle · Pods ≈ 10.7 غ.ب) وكل ما يستثنيه .gitignore. هذا الكوميت **بلا أي تعديل عمداً** حتى يكون كل ما يليه فرقاً مقروءاً مقابل سيرو الأصلي. سيرو نفسه لم يُمسّ. ⚠️ لا يبني بعد: `.env` و`lib/env/env.g.dart` غير متعقَّبين في سيرو (وهذا صحيح — أسرار لكل مستأجر). كل تطبيق فلاتر هنا يحتاج .env خاصاً بانطلق ثم توليد env.g.dart عبر build_runner. لا تُنسخ أسرار سيرو. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* cron_empty_results_to_db.php
|
||||
* سكربت لتفريغ نتائج البوت من ملف results.json إلى قاعدة بيانات MySQL
|
||||
* يُفضل تشغيله برمجياً كل ساعة أو حسب الحاجة
|
||||
*/
|
||||
|
||||
// Allow script to run indefinitely
|
||||
set_time_limit(0);
|
||||
ini_set('memory_limit', '256M');
|
||||
|
||||
// Mock request to satisfy connect.php dependencies if any
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
|
||||
require_once __DIR__ . '/../core/bootstrap.php';
|
||||
require_once __DIR__ . '/../functions.php';
|
||||
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
} catch (Exception $e) {
|
||||
die("Database connection failed: " . $e->getMessage() . "\n");
|
||||
}
|
||||
|
||||
$resultsFile = __DIR__ . '/results.json';
|
||||
|
||||
if (!file_exists($resultsFile)) {
|
||||
die("No results file found.\n");
|
||||
}
|
||||
|
||||
$content = file_get_contents($resultsFile);
|
||||
$data = json_decode($content, true);
|
||||
|
||||
if (empty($data) || !is_array($data)) {
|
||||
die("No data to process or invalid JSON.\n");
|
||||
}
|
||||
|
||||
$insertedCount = 0;
|
||||
$stmt = $con->prepare("INSERT INTO scraped_competitor_prices (task_id, app_name, competitor_name, start_location, end_location, start_lat, start_lng, end_lat, end_lng, price_amount, price_per_km, distance_km, duration_min, currency, country_code) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
|
||||
foreach ($data as $row) {
|
||||
if (isset($row['status']) && $row['status'] !== 'success') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$taskId = $row['task_id'] ?? null;
|
||||
$resultData = $row['result_data'] ?? [];
|
||||
|
||||
$appName = $resultData['app'] ?? $row['app'] ?? 'Unknown';
|
||||
$competitorName = $appName; // Assuming app_name is competitor_name for now
|
||||
|
||||
$startLoc = $resultData['start_location'] ?? $row['start_location'] ?? '';
|
||||
if (empty($startLoc) && !empty($resultData['start_lat'])) {
|
||||
$startLoc = "Lat: {$resultData['start_lat']}, Lng: {$resultData['start_lng']}";
|
||||
}
|
||||
|
||||
$endLoc = $resultData['end_location'] ?? $row['end_location'] ?? '';
|
||||
if (empty($endLoc) && !empty($resultData['end_lat'])) {
|
||||
$endLoc = "Lat: {$resultData['end_lat']}, Lng: {$resultData['end_lng']}";
|
||||
}
|
||||
|
||||
$priceRaw = $resultData['price'] ?? $row['price'] ?? 0;
|
||||
|
||||
$amount = 0.0;
|
||||
$currency = 'JOD';
|
||||
|
||||
if (is_numeric($priceRaw)) {
|
||||
$amount = (float)$priceRaw;
|
||||
} else {
|
||||
$priceStr = (string)$priceRaw;
|
||||
// Match numeric parts (including decimals) and text parts
|
||||
if (preg_match('/([\d\.]+)\s*([A-Za-z]+|د\.ا)/', $priceStr, $matches)) {
|
||||
$amount = (float)$matches[1];
|
||||
$currency = $matches[2];
|
||||
if ($currency === 'د.ا') {
|
||||
$currency = 'JOD';
|
||||
}
|
||||
} else {
|
||||
$amount = (float)$priceStr;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore invalid entries without an amount
|
||||
if ($amount <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$distanceKm = (float)($resultData['distance_km'] ?? 1);
|
||||
$durationMin = isset($resultData['duration_min']) ? (int)$resultData['duration_min'] : null;
|
||||
|
||||
$startLat = $resultData['start_lat'] ?? null;
|
||||
$startLng = $resultData['start_lng'] ?? null;
|
||||
$endLat = $resultData['end_lat'] ?? null;
|
||||
$endLng = $resultData['end_lng'] ?? null;
|
||||
$countryCode = $row['country_code'] ?? 'JO'; // Default
|
||||
|
||||
// --- OSRM Integration (Dynamic Distance & Duration) ---
|
||||
require_once __DIR__ . '/../core/osrm_routing.php';
|
||||
if ($startLat && $endLat && (!$durationMin || $durationMin <= 0)) {
|
||||
$osrmResult = getOsrmRouteDetails($startLat, $startLng, $endLat, $endLng, $countryCode);
|
||||
if ($osrmResult) {
|
||||
$distanceKm = $osrmResult['distance_km']; // Override with accurate OSRM distance
|
||||
$durationMin = $osrmResult['duration_min'];
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------
|
||||
|
||||
if ($distanceKm <= 0) $distanceKm = 1; // Prevent division by zero
|
||||
$pricePerKm = $amount / $distanceKm;
|
||||
|
||||
$countryCode = $row['country_code'] ?? 'JO'; // Default
|
||||
|
||||
if ($stmt->execute([
|
||||
$taskId,
|
||||
$appName,
|
||||
$competitorName,
|
||||
$startLoc,
|
||||
$endLoc,
|
||||
$startLat,
|
||||
$startLng,
|
||||
$endLat,
|
||||
$endLng,
|
||||
$amount,
|
||||
$pricePerKm,
|
||||
$distanceKm,
|
||||
$durationMin,
|
||||
$currency,
|
||||
$countryCode
|
||||
])) {
|
||||
$insertedCount++;
|
||||
} else {
|
||||
echo "Failed to insert task_id: $taskId. Error: " . implode(" ", $stmt->errorInfo()) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the JSON file after successfully inserting data
|
||||
file_put_contents($resultsFile, json_encode([], JSON_PRETTY_PRINT));
|
||||
|
||||
echo "Successfully inserted $insertedCount records into the database and cleared results.json.\n";
|
||||
Reference in New Issue
Block a user