Files
assetmgt/media_scanner.php
“VeLiTi” 24481279d5 Refactor user session handling and permissions management
- Updated session variables to use 'authorization' array instead of 'username' for user identification across multiple files.
- Introduced a new function `getUserPermissions` to consolidate user permissions retrieval based on assigned roles.
- Modified API calls to use the new authorization structure and updated endpoints to v2.
- Enhanced language support by adding 'PL' to the list of supported languages.
- Cleaned up redundant code and improved session management during user login and registration processes.
- Added a new API endpoint for fetching user permissions based on user ID.
2026-01-19 15:29:16 +01:00

528 lines
20 KiB
PHP

<?php
defined(page_security_key) or exit;
$page = 'media_scanner';
//Check if allowed
if (isAllowed($page,$_SESSION['authorization']['profile'],$_SESSION['authorization']['permission'],'R') === 0){
header('location: index.php');
exit;
}
//PAGE Security
$update_allowed = isAllowed($page ,$_SESSION['authorization']['profile'],$_SESSION['authorization']['permission'],'U');
$delete_allowed = isAllowed($page ,$_SESSION['authorization']['profile'],$_SESSION['authorization']['permission'],'D');
$create_allowed = isAllowed($page ,$_SESSION['authorization']['profile'],$_SESSION['authorization']['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">←</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();
?>