I cba with this commit message tbh
This commit is contained in:
@@ -1,88 +1,73 @@
|
||||
<?php
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
require '../../vendor/autoload.php';
|
||||
require '../db.php';
|
||||
require_once '../envLoader.php';
|
||||
require 'scraper.php';
|
||||
loadEnv(__DIR__ . '/../../.env');
|
||||
|
||||
include '../src/session_check.php';
|
||||
include '../session_check.php';
|
||||
checkUserRole(['admin']);
|
||||
|
||||
use Goutte\Client;
|
||||
|
||||
// Start session to get user ID
|
||||
session_start();
|
||||
if (!isset($_SESSION['userId'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'User not authenticated.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check for POST data
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$filamentName = $_POST['productName'] ?? '';
|
||||
$amazonUrl = $_POST['productUrl'] ?? '';
|
||||
$userId = $_SESSION['userId'];
|
||||
|
||||
// Basic validation
|
||||
if (empty($filamentName) || empty($amazonUrl)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Filament name and URL are required.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$client = new Client();
|
||||
try {
|
||||
// Scrape the Amazon page for initial price and other details
|
||||
$crawler = $client->request('GET', $amazonUrl);
|
||||
|
||||
// Scrape Price
|
||||
$whole = $crawler->filter('.a-price-whole')->count() ? $crawler->filter('.a-price-whole')->text() : '0';
|
||||
$fraction = $crawler->filter('.a-price-fraction')->count() ? $crawler->filter('.a-price-fraction')->text() : '00';
|
||||
// Scrape data from Amazon
|
||||
$scrapedData = scrapeAmazonData($amazonUrl);
|
||||
if (!$scrapedData) {
|
||||
throw new Exception('Scraping failed for the provided URL.');
|
||||
}
|
||||
|
||||
$whole = preg_replace('/[^0-9]/', '', $whole);
|
||||
$fraction = preg_replace('/[^0-9]/', '', $fraction);
|
||||
$fraction = strlen($fraction) === 1 ? $fraction . '0' : substr($fraction, 0, 2);
|
||||
$totalPrice = floatval($whole . '.' . $fraction);
|
||||
$price = $scrapedData['price'];
|
||||
$discount = $scrapedData['discount'];
|
||||
$details = $scrapedData['details'];
|
||||
|
||||
// Scrape Filament Details from Table
|
||||
$details = [];
|
||||
$crawler->filter('table.a-normal tr')->each(function ($node) use (&$details) {
|
||||
$label = trim($node->filter('td.a-span3')->text());
|
||||
$value = trim($node->filter('td.a-span9')->text());
|
||||
$details[$label] = $value;
|
||||
});
|
||||
|
||||
|
||||
// Extract details or use default if not found
|
||||
// Extract details or use defaults
|
||||
$brand = $details['Brand'] ?? 'Unknown';
|
||||
$material = $details['Material'] ?? 'Unknown';
|
||||
$color = $details['Colour'] ?? 'Unknown';
|
||||
$filamentWeight = isset($details['Item weight']) ? preg_replace('/[^0-9.]/', '', $details['Item weight']) : 1;
|
||||
if (stripos($details['Item weight'], 'kilograms') !== false || stripos($details['Item weight'], 'kg') !== false) {
|
||||
$filamentWeight = $filamentWeight * 1000; // Convert KG to G
|
||||
$filamentWeight = $filamentWeight * 1000; // Convert KG to G
|
||||
}
|
||||
$itemDiameter = isset($details['Item diameter']) ? preg_replace('/[^0-9.]/', '', $details['Item diameter']) : 1.75;
|
||||
|
||||
// Start a transaction to ensure consistency
|
||||
// Database operations
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Check if filament already exists
|
||||
$stmt = $pdo->prepare("SELECT id FROM filamentTracker WHERE amazonUrl = :amazonUrl");
|
||||
$stmt->execute([':amazonUrl' => $amazonUrl]);
|
||||
$existingFilament = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($existingFilament) {
|
||||
// Filament exists – just update the price history
|
||||
$filamentId = $existingFilament['id'];
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO filamentPriceHistory (filamentId, price)
|
||||
VALUES (:filamentId, :price)
|
||||
INSERT INTO filamentPriceHistory (filamentId, price, currentDiscount)
|
||||
VALUES (:filamentId, :price, :currentDiscount)
|
||||
");
|
||||
$stmt->execute([
|
||||
':filamentId' => $filamentId,
|
||||
':price' => $totalPrice
|
||||
':price' => $price,
|
||||
':currentDiscount' => $discount
|
||||
]);
|
||||
$message = 'Filament price updated successfully.';
|
||||
$message = 'Filament price and discount updated successfully.';
|
||||
} else {
|
||||
// Insert new filament into filamentTracker
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO filamentTracker (userId, filamentName, amazonUrl, filamentWeight, brand, material, color, itemDiameter)
|
||||
VALUES (:userId, :filamentName, :amazonUrl, :filamentWeight, :brand, :material, :color, :itemDiameter)
|
||||
@@ -98,29 +83,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
':itemDiameter' => $itemDiameter
|
||||
]);
|
||||
|
||||
// Get the last inserted filament ID
|
||||
$filamentId = $pdo->lastInsertId();
|
||||
|
||||
// Insert initial price into filamentPriceHistory
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO filamentPriceHistory (filamentId, price)
|
||||
VALUES (:filamentId, :price)
|
||||
INSERT INTO filamentPriceHistory (filamentId, price, currentDiscount)
|
||||
VALUES (:filamentId, :price, :currentDiscount)
|
||||
");
|
||||
$stmt->execute([
|
||||
':filamentId' => $filamentId,
|
||||
':price' => $totalPrice
|
||||
':price' => $price,
|
||||
':currentDiscount' => $discount
|
||||
]);
|
||||
|
||||
$message = $filamentName . ' Filament added successfully and price tracked.';
|
||||
$message = "$filamentName added successfully and price with discount tracked.";
|
||||
}
|
||||
|
||||
// Commit the transaction
|
||||
$pdo->commit();
|
||||
|
||||
echo json_encode(['status' => 'success', 'message' => $message]);
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to scrape or insert data. Error: ' . $e->getMessage()]);
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid request method.']);
|
||||
|
||||
@@ -9,7 +9,7 @@ include '../src/session_check.php';
|
||||
header('Content-Type: application/json');
|
||||
|
||||
try {
|
||||
// Fetch all filament prices with a limit of 180 entries per filament using JOIN
|
||||
// Fetch all filament prices with the latest discount
|
||||
$stmt = $pdo->query("
|
||||
SELECT ft.filamentName,
|
||||
ft.brand,
|
||||
@@ -17,6 +17,7 @@ try {
|
||||
ft.color,
|
||||
ft.amazonUrl,
|
||||
fp.price,
|
||||
fp.currentDiscount,
|
||||
fp.recordedAt
|
||||
FROM filamentTracker ft
|
||||
JOIN filamentPriceHistory fp ON ft.id = fp.filamentId
|
||||
@@ -27,11 +28,11 @@ try {
|
||||
ROW_NUMBER() OVER (PARTITION BY filamentId ORDER BY recordedAt DESC) as rn
|
||||
FROM filamentPriceHistory
|
||||
) ranked
|
||||
WHERE rn <= 180
|
||||
WHERE rn <= 280
|
||||
) filtered ON fp.filamentId = filtered.filamentId AND fp.recordedAt = filtered.recordedAt
|
||||
ORDER BY ft.filamentName, fp.recordedAt ASC
|
||||
");
|
||||
|
||||
|
||||
$filaments = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$result = [];
|
||||
@@ -39,14 +40,15 @@ try {
|
||||
// Format data for charts (grouped by filament)
|
||||
foreach ($filaments as $filament) {
|
||||
$name = $filament['filamentName'];
|
||||
|
||||
|
||||
if (!isset($result[$name])) {
|
||||
$result[$name] = [
|
||||
'brand' => $filament['brand'],
|
||||
'material' => $filament['material'],
|
||||
'color' => $filament['color'],
|
||||
'amazonUrl' => $filament['amazonUrl'],
|
||||
'prices' => []
|
||||
'prices' => [],
|
||||
'currentDiscount' => $filament['currentDiscount'] ?? 0 // Include the latest discount
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
require '/mnt/www-live/TechOdyssey_Designs_Dashboard/vendor/autoload.php';
|
||||
|
||||
use Goutte\Client;
|
||||
|
||||
function scrapeAmazonData($url) {
|
||||
$client = new Client();
|
||||
|
||||
try {
|
||||
$crawler = $client->request('GET', $url);
|
||||
|
||||
// Scrape price
|
||||
$whole = $crawler->filter('.a-price-whole')->count() ? $crawler->filter('.a-price-whole')->text() : '0';
|
||||
$fraction = $crawler->filter('.a-price-fraction')->count() ? $crawler->filter('.a-price-fraction')->text() : '00';
|
||||
$whole = preg_replace('/[^0-9]/', '', $whole);
|
||||
$fraction = preg_replace('/[^0-9]/', '', $fraction);
|
||||
$fraction = strlen($fraction) === 1 ? $fraction . '0' : substr($fraction, 0, 2);
|
||||
$totalPrice = floatval($whole . '.' . $fraction);
|
||||
|
||||
// Scrape discount
|
||||
$discount = $crawler->filter('.savingsPercentage')->count()
|
||||
? $crawler->filter('.savingsPercentage')->text()
|
||||
: null;
|
||||
if ($discount) {
|
||||
$discount = preg_replace('/[^0-9]/', '', $discount);
|
||||
} else {
|
||||
$discount = 0; // Default to 0 if no discount is found
|
||||
}
|
||||
|
||||
// Scrape additional details
|
||||
$details = [];
|
||||
$crawler->filter('table.a-normal tr')->each(function ($node) use (&$details) {
|
||||
$label = trim($node->filter('td.a-span3')->text());
|
||||
$value = trim($node->filter('td.a-span9')->text());
|
||||
$details[$label] = $value;
|
||||
});
|
||||
|
||||
return [
|
||||
'price' => $totalPrice,
|
||||
'discount' => $discount,
|
||||
'details' => $details
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
return null; // Return null if scraping fails
|
||||
}
|
||||
}
|
||||
@@ -2,31 +2,9 @@
|
||||
require '/mnt/www-live/TechOdyssey_Designs_Dashboard/vendor/autoload.php';
|
||||
require '/mnt/www-live/TechOdyssey_Designs_Dashboard/src/db.php';
|
||||
require_once '/mnt/www-live/TechOdyssey_Designs_Dashboard/src/envLoader.php';
|
||||
require 'scraper.php';
|
||||
loadEnv(__DIR__ . '/../../.env');
|
||||
|
||||
use Goutte\Client;
|
||||
|
||||
// Function to scrape price
|
||||
function scrapePrice($url) {
|
||||
$client = new Client(); // Reinitialize client for each request
|
||||
try {
|
||||
$crawler = $client->request('GET', $url);
|
||||
|
||||
$whole = $crawler->filter('.a-price-whole')->count() ? $crawler->filter('.a-price-whole')->text() : '0';
|
||||
$fraction = $crawler->filter('.a-price-fraction')->count() ? $crawler->filter('.a-price-fraction')->text() : '00';
|
||||
|
||||
$whole = preg_replace('/[^0-9]/', '', $whole);
|
||||
$fraction = preg_replace('/[^0-9]/', '', $fraction);
|
||||
$fraction = strlen($fraction) === 1 ? $fraction . '0' : substr($fraction, 0, 2);
|
||||
|
||||
$totalPrice = floatval($whole . '.' . $fraction);
|
||||
|
||||
return $totalPrice;
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch all filaments
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT * FROM filamentTracker");
|
||||
@@ -36,20 +14,21 @@ try {
|
||||
$amazonUrl = $filament['amazonUrl'];
|
||||
$filamentId = $filament['id'];
|
||||
|
||||
// Scrape price
|
||||
$totalPrice = scrapePrice($amazonUrl);
|
||||
// Use the scraper function to fetch price and discount
|
||||
$scrapedData = scrapeAmazonData($amazonUrl);
|
||||
|
||||
if ($totalPrice !== null && $totalPrice > 0) {
|
||||
if ($scrapedData && $scrapedData['price'] > 0) {
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO filamentPriceHistory (filamentId, price)
|
||||
VALUES (:filamentId, :price)
|
||||
INSERT INTO filamentPriceHistory (filamentId, price, currentDiscount)
|
||||
VALUES (:filamentId, :price, :currentDiscount)
|
||||
");
|
||||
$stmt->execute([
|
||||
':filamentId' => $filamentId,
|
||||
':price' => $totalPrice
|
||||
':price' => $scrapedData['price'],
|
||||
':currentDiscount' => $scrapedData['discount']
|
||||
]);
|
||||
|
||||
echo "Updated price for {$filament['filamentName']}: £{$totalPrice}\n";
|
||||
echo "Updated price for {$filament['filamentName']}: £{$scrapedData['price']}, Discount: {$scrapedData['discount']}%\n";
|
||||
} else {
|
||||
echo "Failed to update {$filament['filamentName']} (no price found or £0).\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user