528 lines
20 KiB
PHP
528 lines
20 KiB
PHP
<?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();
|
|
?>
|