CMXX - Dealers
This commit is contained in:
528
media_scanner.php
Normal file
528
media_scanner.php
Normal file
@@ -0,0 +1,528 @@
|
||||
<?php
|
||||
defined(page_security_key) or exit;
|
||||
|
||||
$page = 'media_scanner';
|
||||
//Check if allowed
|
||||
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
|
||||
header('location: index.php');
|
||||
exit;
|
||||
}
|
||||
//PAGE Security
|
||||
$update_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'U');
|
||||
$delete_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'D');
|
||||
$create_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'C');
|
||||
|
||||
// Check if domain is passed in URL
|
||||
$autoFetchDomain = isset($_GET['domain']) ? $_GET['domain'] : '';
|
||||
|
||||
// check if rowID is passed in url
|
||||
$autoFetchRowID = isset($_GET['rowID']) ? $_GET['rowID'] : '';
|
||||
if ($autoFetchRowID != ''){
|
||||
$_SESSION['autoFetchRowID'] = $_GET['rowID'];
|
||||
}
|
||||
|
||||
// This variable will be used in the JavaScript to trigger auto-fetch
|
||||
$autoFetch = !empty($autoFetchDomain);
|
||||
|
||||
if ($create_allowed === 1){
|
||||
|
||||
// Check if this is an AJAX request for fetching images
|
||||
if (isset($_POST['action']) && $_POST['action'] === 'fetch_images') {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$domain = isset($_POST['domain']) ? $_POST['domain'] : '';
|
||||
|
||||
// Validate domain
|
||||
if (empty($domain)) {
|
||||
echo json_encode(['error' => 'Please provide a valid domain']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Add http:// if not present
|
||||
if (!preg_match('~^(?:f|ht)tps?://~i', $domain)) {
|
||||
$domain = 'http://' . $domain;
|
||||
}
|
||||
|
||||
// Try to get the content from the domain
|
||||
try {
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'timeout' => 30,
|
||||
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||
]
|
||||
]);
|
||||
|
||||
$content = @file_get_contents($domain, false, $context);
|
||||
|
||||
if ($content === false) {
|
||||
echo json_encode(['error' => 'Could not access the domain']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Create a DOM object
|
||||
$dom = new DOMDocument();
|
||||
|
||||
// Suppress warnings from invalid HTML
|
||||
@$dom->loadHTML($content);
|
||||
|
||||
// Extract all image elements
|
||||
$images = $dom->getElementsByTagName('img');
|
||||
$imageUrls = [];
|
||||
|
||||
foreach ($images as $image) {
|
||||
$src = $image->getAttribute('src');
|
||||
|
||||
// Skip empty sources
|
||||
if (empty($src)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle relative URLs
|
||||
if (strpos($src, 'http') !== 0) {
|
||||
// If src starts with //, add http:
|
||||
if (strpos($src, '//') === 0) {
|
||||
$src = 'http:' . $src;
|
||||
}
|
||||
// If src starts with /, add domain
|
||||
elseif (strpos($src, '/') === 0) {
|
||||
$parsedUrl = parse_url($domain);
|
||||
$baseUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host'];
|
||||
$src = $baseUrl . $src;
|
||||
}
|
||||
// Otherwise, assume it's a relative path
|
||||
else {
|
||||
$parsedUrl = parse_url($domain);
|
||||
$baseUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host'];
|
||||
$path = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';
|
||||
|
||||
// Remove filename from path if it exists
|
||||
$path = preg_replace('/\/[^\/]*$/', '/', $path);
|
||||
|
||||
$src = $baseUrl . $path . $src;
|
||||
}
|
||||
}
|
||||
|
||||
// Add to our list of URLs if it's not already there
|
||||
if (!in_array($src, $imageUrls)) {
|
||||
$imageUrls[] = $src;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the list of images
|
||||
echo json_encode(['images' => $imageUrls]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['error' => 'Error: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Important: exit after sending JSON to avoid sending HTML too
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check if this is an AJAX request for uploading images
|
||||
if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Get the raw POST data and decode the JSON
|
||||
$jsonData = file_get_contents('php://input');
|
||||
$data = json_decode($jsonData, true);
|
||||
|
||||
// Check if we have images to process
|
||||
if (!isset($data['images']) || empty($data['images'])) {
|
||||
echo json_encode(['error' => 'No images provided']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Directory to save images
|
||||
$uploadDir = 'assets/images/media/';
|
||||
|
||||
$successCount = 0;
|
||||
$errorMessages = [];
|
||||
|
||||
// Process each image URL
|
||||
foreach ($data['images'] as $imageUrl) {
|
||||
// Generate a unique filename
|
||||
$fileTitle = uniqid() . '_' . basename(parse_url($imageUrl, PHP_URL_PATH));
|
||||
$fileName = $uploadDir . $fileTitle;
|
||||
|
||||
// Clean the filename to avoid security issues
|
||||
//$fileName = preg_replace('/[^a-zA-Z0-9_.-]/', '_', $fileName);
|
||||
|
||||
try {
|
||||
// Create a context with a timeout for file_get_contents
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'timeout' => 30,
|
||||
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
||||
]
|
||||
]);
|
||||
|
||||
// Fetch the image
|
||||
$imageContent = @file_get_contents($imageUrl, false, $context);
|
||||
|
||||
if ($imageContent === false) {
|
||||
$errorMessages[] = "Failed to download: $imageUrl";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save the image
|
||||
if (file_put_contents($fileName, $imageContent)) {
|
||||
|
||||
//STORE MEDIA DATA
|
||||
$payload = [
|
||||
'title' => $fileTitle,
|
||||
'full_path' => $fileName
|
||||
];
|
||||
$payload = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||
//API call
|
||||
$responses = ioServer('/v2/media', $payload);
|
||||
$inserted_media = json_decode($responses,true);
|
||||
|
||||
//STORE MEDIA RELATED TO DEALER WHEN ROWID IS SEND
|
||||
if (isset($_SESSION['autoFetchRowID']) && $inserted_media['rowID'] !=''){
|
||||
$dealer_id = $_SESSION['autoFetchRowID'];
|
||||
$payload_2 = json_encode(array("rowID" => $dealer_id, "dealer_media" => $inserted_media['rowID']), JSON_UNESCAPED_UNICODE);
|
||||
//API call
|
||||
ioServer('/v2/dealers', $payload_2);
|
||||
}
|
||||
$successCount++;
|
||||
} else {
|
||||
$errorMessages[] = "Failed to save: $imageUrl";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$errorMessages[] = "Error processing $imageUrl: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Return the results
|
||||
$result = [
|
||||
'success' => $successCount,
|
||||
'total' => count($data['images'])
|
||||
];
|
||||
|
||||
if (!empty($errorMessages)) {
|
||||
$result['errors'] = $errorMessages;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//RESET S_SESSION VARIABLE
|
||||
if (isset($_SESSION['autoFetchRowID'])){
|
||||
unset($_SESSION['autoFetchRowID']);
|
||||
}
|
||||
echo json_encode($result);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
template_header('Media_scanner', 'media_scanner', 'manage');
|
||||
|
||||
$view ='
|
||||
<style>
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.domain-input {
|
||||
flex-grow: 1;
|
||||
margin-right: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.thumbnail {
|
||||
position: relative;
|
||||
height: 150px;
|
||||
border: 1px solid #ddd;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.thumbnail:hover {
|
||||
transform: scale(1.03);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
.thumbnail img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.thumbnail.selected {
|
||||
border: 3px solid #4CAF50;
|
||||
}
|
||||
.thumbnail-overlay {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
color: white;
|
||||
padding: 5px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
.thumbnail:hover .thumbnail-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
.selected-count {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
border-radius: 15px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.status {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.status.success {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
}
|
||||
.status.error {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
}
|
||||
.loading {
|
||||
display: none;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.spinner {
|
||||
border: 5px solid #f3f3f3;
|
||||
border-top: 5px solid #4CAF50;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
|
||||
<h2 class="responsive-width-100">Media scanner</h2>
|
||||
<a href="index.php?page='.$_SESSION['origin'].'" class="btn alt mar-right-2">'.$button_cancel.'</a>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="header" '.(($autoFetch) ? 'style="display:none;"' : '').'>
|
||||
<input type="text" class="domain-input" id="domainInput" placeholder="Enter domain (e.g., example.com)" '.(($autoFetch) ? 'value="'.htmlspecialchars($autoFetchDomain).'"' : '').'/>
|
||||
<button id="fetchBtn" class="btn">Fetch Images</button>
|
||||
</div>
|
||||
|
||||
<div class="loading" id="loadingIndicator">
|
||||
<div class="spinner"></div>
|
||||
<p>Loading images...</p>
|
||||
</div>
|
||||
|
||||
<div id="statusMessage"></div>
|
||||
|
||||
<div class="gallery" id="imageGallery"></div>
|
||||
|
||||
<div class="header" style="margin-top: 20px;">
|
||||
<button id="uploadBtn" class="btn" disabled>Upload Selected Images <span id="selectedCount" class="selected-count">0</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener(\'DOMContentLoaded\', function() {
|
||||
const domainInput = document.getElementById(\'domainInput\');
|
||||
const fetchBtn = document.getElementById(\'fetchBtn\');
|
||||
const uploadBtn = document.getElementById(\'uploadBtn\');
|
||||
const imageGallery = document.getElementById(\'imageGallery\');
|
||||
const statusMessage = document.getElementById(\'statusMessage\');
|
||||
const selectedCount = document.getElementById(\'selectedCount\');
|
||||
const loadingIndicator = document.getElementById(\'loadingIndicator\');
|
||||
|
||||
let selectedImages = [];
|
||||
|
||||
';
|
||||
|
||||
if ($autoFetch){
|
||||
// Automatically trigger fetch when page loads with domain parameter
|
||||
// Small delay to ensure DOM is fully loaded
|
||||
$view .= 'setTimeout(function() {fetchBtn.click();}, 500)';
|
||||
}
|
||||
$view .= '
|
||||
// Fetch images from domain
|
||||
fetchBtn.addEventListener(\'click\', function() {
|
||||
const domain = domainInput.value.trim();
|
||||
|
||||
if (!domain) {
|
||||
showStatus(\'Please enter a valid domain\', \'error\');
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset state
|
||||
imageGallery.innerHTML = \'\';
|
||||
selectedImages = [];
|
||||
updateSelectedCount();
|
||||
uploadBtn.disabled = true;
|
||||
|
||||
// Show loading indicator
|
||||
loadingIndicator.style.display = \'block\';
|
||||
showStatus(\'\', \'\');
|
||||
|
||||
// Key change: send to the current page but with a special parameter
|
||||
fetch(window.location.href, {
|
||||
method: \'POST\',
|
||||
headers: {
|
||||
\'Content-Type\': \'application/x-www-form-urlencoded\',
|
||||
},
|
||||
body: \'action=fetch_images&domain=\' + encodeURIComponent(domain)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
loadingIndicator.style.display = \'none\';
|
||||
|
||||
if (data.error) {
|
||||
showStatus(data.error, \'error\');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.images || data.images.length === 0) {
|
||||
showStatus(\'No images found on this domain\', \'error\');
|
||||
return;
|
||||
}
|
||||
|
||||
showStatus(`Found ${data.images.length} images`, \'success\');
|
||||
|
||||
// Create thumbnails
|
||||
data.images.forEach((imageUrl, index) => {
|
||||
const thumbnail = document.createElement(\'div\');
|
||||
thumbnail.className = \'thumbnail\';
|
||||
thumbnail.dataset.url = imageUrl;
|
||||
|
||||
const img = document.createElement(\'img\');
|
||||
img.src = imageUrl;
|
||||
img.alt = `Image ${index + 1}`;
|
||||
img.onerror = function() {
|
||||
// Replace with placeholder if image fails to load
|
||||
this.src = \'https://via.placeholder.com/200x150?text=Image+Error\';
|
||||
};
|
||||
|
||||
const overlay = document.createElement(\'div\');
|
||||
overlay.className = \'thumbnail-overlay\';
|
||||
overlay.textContent = \'Click to select\';
|
||||
|
||||
thumbnail.appendChild(img);
|
||||
thumbnail.appendChild(overlay);
|
||||
imageGallery.appendChild(thumbnail);
|
||||
|
||||
// Add click event to select/deselect
|
||||
thumbnail.addEventListener(\'click\', function() {
|
||||
this.classList.toggle(\'selected\');
|
||||
|
||||
const imageUrl = this.dataset.url;
|
||||
const index = selectedImages.indexOf(imageUrl);
|
||||
|
||||
if (index === -1) {
|
||||
selectedImages.push(imageUrl);
|
||||
this.querySelector(\'.thumbnail-overlay\').textContent = \'Selected\';
|
||||
} else {
|
||||
selectedImages.splice(index, 1);
|
||||
this.querySelector(\'.thumbnail-overlay\').textContent = \'Click to select\';
|
||||
}
|
||||
|
||||
updateSelectedCount();
|
||||
});
|
||||
});
|
||||
|
||||
uploadBtn.disabled = false;
|
||||
})
|
||||
.catch(error => {
|
||||
loadingIndicator.style.display = \'none\';
|
||||
showStatus(\'Error fetching images: \' + error.message, \'error\');
|
||||
});
|
||||
});
|
||||
|
||||
// Upload selected images
|
||||
uploadBtn.addEventListener(\'click\', function() {
|
||||
if (selectedImages.length === 0) {
|
||||
showStatus(\'Please select at least one image\', \'error\');
|
||||
return;
|
||||
}
|
||||
|
||||
showStatus(\'Uploading images...\', \'success\');
|
||||
loadingIndicator.style.display = \'block\';
|
||||
|
||||
fetch(window.location.href, {
|
||||
method: \'POST\',
|
||||
headers: {
|
||||
\'Content-Type\': \'application/json\',
|
||||
},
|
||||
body: JSON.stringify({ images: selectedImages })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
loadingIndicator.style.display = \'none\';
|
||||
|
||||
if (data.error) {
|
||||
showStatus(data.error, \'error\');
|
||||
return;
|
||||
}
|
||||
|
||||
showStatus(`Successfully uploaded ${data.success} images`, \'success\');
|
||||
|
||||
// Clear selections after successful upload
|
||||
document.querySelectorAll(\'.thumbnail.selected\').forEach(thumbnail => {
|
||||
thumbnail.classList.remove(\'selected\');
|
||||
thumbnail.querySelector(\'.thumbnail-overlay\').textContent = \'Click to select\';
|
||||
});
|
||||
|
||||
selectedImages = [];
|
||||
updateSelectedCount();
|
||||
})
|
||||
.catch(error => {
|
||||
loadingIndicator.style.display = \'none\';
|
||||
showStatus(\'Error uploading images: \' + error.message, \'error\');
|
||||
});
|
||||
});
|
||||
|
||||
// Helper functions
|
||||
function updateSelectedCount() {
|
||||
selectedCount.textContent = selectedImages.length;
|
||||
uploadBtn.disabled = selectedImages.length === 0;
|
||||
}
|
||||
|
||||
function showStatus(message, type) {
|
||||
if (!message) {
|
||||
statusMessage.innerHTML = \'\';
|
||||
return;
|
||||
}
|
||||
|
||||
statusMessage.innerHTML = message;
|
||||
statusMessage.className = \'status \' + type;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
';
|
||||
|
||||
//Output
|
||||
echo $view;
|
||||
|
||||
template_footer();
|
||||
?>
|
||||
Reference in New Issue
Block a user