fix filename bug

This commit is contained in:
François
2026-10-19 09:31:56 +02:00
parent 3f1a8b14cb
commit 9c0eba8d2d
5 changed files with 219 additions and 35 deletions
+6 -5
View File
@@ -1,8 +1,9 @@
<?php <?php
return [ return [
'routes' => [ 'routes' => [
['name' => 'page#main', 'url' => '/', 'verb' => 'GET'], ['name' => 'page#main', 'url' => '/', 'verb' => 'GET'],
['name' => 'page#zipDrop', 'url' => '/zipDrop', 'verb' => 'GET'], ['name' => 'page#zipDrop', 'url' => '/zipDrop', 'verb' => 'GET'],
['name' => 'page#getFile', 'url' => '/getFile', 'verb' => 'GET'] ['name' => 'page#getFile', 'url' => '/getFile', 'verb' => 'GET'],
] ['name' => 'page#getFileMetadata', 'url' => '/getFileMetadata', 'verb' => 'GET']
]
]; ];
+94 -1
View File
@@ -134,4 +134,97 @@ class PageController extends Controller {
return new JsonResponse(['parameters' => $parameters, 'status' => 500]); // 500 Internal Server Error return new JsonResponse(['parameters' => $parameters, 'status' => 500]); // 500 Internal Server Error
} }
} }
}
// Nouvelle méthode pour récupérer les métadonnées du fichier
#[NoCSRFRequired]
#[NoAdminRequired]
#[OpenAPI(OpenAPI::SCOPE_IGNORE)]
#[FrontpageRoute(verb: 'GET', url: '/getFileMetadata')]
public function getFileMetadata(): JsonResponse {
$zipUrl = $this->request->getParam('url');
// Initialiser les paramètres de réponse
$parameters = [
'status' => 'error',
'message' => '',
'filename' => null,
'mime' => null,
'size' => null
];
// Valider l'URL
if (!$zipUrl || filter_var($zipUrl, FILTER_VALIDATE_URL) === false) {
$parameters['message'] = 'Invalid URL';
return new JsonResponse(['parameters' => $parameters], 400);
}
try {
// Initialiser cURL pour une requête HEAD
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $zipUrl);
curl_setopt($ch, CURLOPT_HEADER, true); // Récupérer les en-têtes
curl_setopt($ch, CURLOPT_NOBODY, true); // Requête HEAD (pas de corps)
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// Exécuter la requête HEAD
$headerResponse = curl_exec($ch);
// Gérer les erreurs cURL
if (curl_errno($ch)) {
$parameters['message'] = 'cURL error: ' . curl_error($ch);
curl_close($ch);
return new JsonResponse(['parameters' => $parameters], 500);
}
// Récupérer le code HTTP
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
$parameters['message'] = "HTTP error: $httpCode";
return new JsonResponse(['parameters' => $parameters], $httpCode);
}
// Extraire Content-Disposition depuis les en-têtes
$contentDisposition = '';
if (preg_match('/Content-Disposition: (.+)/i', $headerResponse, $matches)) {
$contentDisposition = $matches[1];
}
// Extraire le nom du fichier depuis Content-Disposition
$filename = basename(parse_url($zipUrl, PHP_URL_PATH)); // Nom par défaut
if ($contentDisposition) {
preg_match('/filename="?([^"]+)"?/i', $contentDisposition, $filenameMatches);
if (!empty($filenameMatches[1])) {
$filename = $filenameMatches[1];
}
}
// Extraire d'autres métadonnées (optionnel)
$contentType = '';
if (preg_match('/Content-Type: (.+)/i', $headerResponse, $typeMatches)) {
$contentType = $typeMatches[1];
}
$contentLength = 0;
if (preg_match('/Content-Length: (\d+)/i', $headerResponse, $lengthMatches)) {
$contentLength = (int)$lengthMatches[1];
}
// Construire la réponse de succès
$parameters['status'] = 'success';
$parameters['message'] = 'Metadata retrieved successfully';
$parameters['filename'] = $filename;
$parameters['mime'] = $contentType;
$parameters['size'] = $contentLength;
return new JsonResponse(['parameters' => $parameters], 200);
} catch (\Exception $e) {
$parameters['message'] = 'Exception: ' . $e->getMessage();
return new JsonResponse(['parameters' => $parameters], 500);
}
}
}
+104 -21
View File
@@ -1,18 +1,53 @@
<template> <template>
<div id="app" class="h-full w-full dark:bg-black/80 bg-white/80"> <div id="app" class="h-full w-full dark:bg-black/80 bg-white/80">
<!-- Conteneur principal, ajustement en flex-row à partir de sm --> <!-- Mode normal -->
<div class="h-full w-full flex flex-col sm:flex-row"> <div v-if="!isTestMode" class="h-full w-full flex flex-col sm:flex-row">
<!-- Première section --> <!-- Première section -->
<div <div
class="w-full sm:w-1/3 max-sm:h-2/5 p-4 sm:m-6 sm:mr-0 rounded-xl dark:bg-NcBlack/40 bg-white/80"> class="w-full sm:w-1/3 max-sm:h-2/5 p-4 sm:m-6 sm:mr-0 rounded-xl dark:bg-NcBlack/30 bg-white/80">
<WebContentViewer :translate="translate" @file-upload="handleFileUpload" @dragEnded="toggleDragEnded" :zipUrl="zipUrl"/> <WebContentViewer :translate="translate" @file-upload="handleFileUpload" @dragEnded="toggleDragEnded" :zipUrl="zipUrl"/>
</div> </div>
<!-- Deuxième section --> <!-- Deuxième section -->
<div <div
class="w-full sm:w-2/3 max-sm:h-3/5 p-4 sm:m-6 sm:ml-4 dark:bg-NcBlack bg-white rounded-xl"> class="w-full sm:w-2/3 max-sm:h-3/5 p-4 sm:m-6 sm:ml-4 dark:bg-NcBlack/30 bg-white rounded-xl">
<FileTable :file="sharedFile" :dragEnded="dragEnded" :translate="translate" @dragEnded="toggleDragEnded"/> <FileTable :file="sharedFile" :dragEnded="dragEnded" :translate="translate" @dragEnded="toggleDragEnded"/>
</div> </div>
</div> </div>
<!-- Mode test -->
<div v-if="isTestMode" class="h-full w-full p-4">
<div class="bg-white dark:bg-NcBlack/30 rounded-xl p-6">
<h1 class="text-2xl font-bold mb-4 text-gray-800 dark:text-white">🧪 Mode Test</h1>
<!-- Champ pour l'URL de test -->
<div class="mb-4">
<label for="testUrl" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
URL de test :
</label>
<input
id="testUrl"
v-model="testUrl"
type="text"
class="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-NcBlack/50 text-gray-800 dark:text-white"
placeholder="https://example.com/fichier.odt"
/>
</div>
<!-- Bouton pour lancer le test -->
<button
@click="runTest"
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition"
>
Tester
</button>
<!-- Résultats du test -->
<div v-if="testResults" class="mt-6 p-4 bg-gray-100 dark:bg-NcBlack/20 rounded-md">
<h2 class="font-semibold mb-2 text-gray-800 dark:text-white">Résultats :</h2>
<pre class="text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap">{{ testResults }}</pre>
</div>
</div>
</div>
</div> </div>
</template> </template>
@@ -35,30 +70,78 @@ export default {
name: 'App', name: 'App',
components: { components: {
FileTable, FileTable,
WebContentViewer WebContentViewer
}, },
data() { data() {
let zipUrl = document.getElementById('archiveInfos').getAttribute('dataarchiveurl'); let zipUrl = document.getElementById('archiveInfos').getAttribute('dataarchiveurl');
//console.log(zipUrl)
return { return {
zipUrl, zipUrl,
sharedFile: null, sharedFile: null,
dragEnded: false, dragEnded: false,
// Nouveaux champs pour le mode test
isTestMode: false,
testUrl: '',
testResults: '',
}; };
}, },
methods: { mounted() {
handleFileUpload(file) { // Vérifier si l'URL contient ?test=true
this.sharedFile = file; const urlParams = new URLSearchParams(window.location.search);
}, this.isTestMode = urlParams.get('test') === 'true';
toggleDragEnded(){ },
this.dragEnded = !this.dragEnded; methods: {
this.sharedFile = null; handleFileUpload(file) {
}, this.sharedFile = file;
translate(id) { },
return i18next.t(id) toggleDragEnded() {
}, this.dragEnded = !this.dragEnded;
}, this.sharedFile = null;
} },
translate(id) {
return i18next.t(id);
},
// Nouvelle méthode pour exécuter les tests
async runTest() {
if (!this.testUrl) {
this.testResults = "❌ Veuillez entrer une URL de test.";
return;
}
try {
this.testResults = "⏳ Test en cours...";
// Tester la fonction getFilenameFromUrl
const filename = await this.getFilenameFromUrl(this.testUrl);
this.testResults = `✅ Nom2 du fichier extrait : ${filename}\n\n`;
// Tester la fonction loadZipContent (si applicable)
// Note: Vous pouvez adapter cette partie pour tester d'autres fonctions
// this.testResults += `Contenu chargé : ${JSON.stringify(this.zipContent, null, 2)}`;
} catch (error) {
this.testResults = `❌ Erreur : ${error.message}`;
console.error("Erreur lors du test :", error);
}
},
// Fonction pour extraire le nom du fichier depuis une URL
async getFilenameFromUrl(fileUrl) {
try {
const metadataUrl = OC.generateUrl('/apps/webtransfer/getFileMetadata?url=' + encodeURIComponent(fileUrl));
const metadataResponse = await fetch(metadataUrl);
const metadataJson = await metadataResponse.json();
const originalFileName = metadataJson.parameters.filename;
console.log("Nom du fichier :", originalFileName);
return "originalFileName: " + originalFileName + " json:" + metadataJson;
} catch (error) {
console.error("Erreur dans getFilenameFromUrl :", error);
return "erreur" + error; //fileUrl.split('/').pop();
}
}
},
};
</script> </script>
<style> <style>
+1 -1
View File
@@ -78,7 +78,7 @@
@dragleave.prevent="onDragLeave($event)" @dragend="onDragEnd"> @dragleave.prevent="onDragLeave($event)" @dragend="onDragEnd">
<div v-for="file in files" :key="file.filename" <div v-for="file in files" :key="file.filename"
class="flex h-16 items-center dark:hover:bg-NcGray hover:bg-NcWhite rounded-lg border-b last:border-b-0 border-gray-300 cursor-pointer" class="flex h-16 items-center dark:hover:bg-NcGray/20 hover:bg-NcWhite rounded-lg border-b last:border-b-0 border-gray-300 cursor-pointer"
@click="handleClickElem(file)"> @click="handleClickElem(file)">
<!-- Nom --> <!-- Nom -->
+14 -7
View File
@@ -89,7 +89,7 @@
</template> </template>
<script> <script>
import NcBreadcrumbs from '@nextcloud/vue/dist/Components/NcBreadcrumbs.js'; import NcBreadcrumbs from '@nextcloud/vue/dist/Components/NcBreadcrumbs.js';
import NcBreadcrumb from '@nextcloud/vue/dist/Components/NcBreadcrumb.js'; import NcBreadcrumb from '@nextcloud/vue/dist/Components/NcBreadcrumb.js';
import JSZip from 'jszip'; import JSZip from 'jszip';
import ChevronRightIcon from 'vue-material-design-icons/ChevronRight.vue'; import ChevronRightIcon from 'vue-material-design-icons/ChevronRight.vue';
@@ -183,14 +183,18 @@ export default {
methods: { methods: {
async loadZipContent() { async loadZipContent() {
try { try {
const metadataUrl = OC.generateUrl('/apps/webtransfer/getFileMetadata?url=' + encodeURIComponent(this.zipUrl));
const metadataResponse = await fetch(metadataUrl);
const metadataJson = await metadataResponse.json();
const originalFileName = metadataJson.parameters.filename;
var baseUrl = OC.generateUrl('/apps/webtransfer/getFile'); var baseUrl = OC.generateUrl('/apps/webtransfer/getFile');
let fullUrl = baseUrl + '?url=' + encodeURIComponent(this.zipUrl); let fullUrl = baseUrl + '?url=' + encodeURIComponent(this.zipUrl);
let response = await fetch(fullUrl); let response = await fetch(fullUrl);
let responseJson = await response.json(); let responseJson = await response.json();
const zipData = responseJson.parameters.data; const zipData = responseJson.parameters.data;
const first10Chars = zipData.substring(0,4);
const first10Chars = zipData.substring(0,4);
if(this.mode === "zip") { if(this.mode === "zip") {
// Check si le debut du fichier correspond a celui d'un zip // Check si le debut du fichier correspond a celui d'un zip
@@ -268,9 +272,12 @@ export default {
try { try {
let type = await fileTypeFromBuffer(uint8Array); let type = await fileTypeFromBuffer(uint8Array);
const file = new File([uint8Array], 'file.' + type.ext, {type: type.mime});
const file = new File([uint8Array], originalFileName, { type: type.mime });
//const file = new File([uint8Array], 'file.' + type.ext, {type: type.mime});
let entry = [{ let entry = [{
name: file.name, name: file.name,
isDirectory: false, isDirectory: false,
size: file.size, size: file.size,
content: uint8Array, // Initialiser 'content' pour les fichiers content: uint8Array, // Initialiser 'content' pour les fichiers
@@ -482,4 +489,4 @@ export default {
<style scoped> <style scoped>
/* Ajoutez ici des styles si nécessaire */ /* Ajoutez ici des styles si nécessaire */
</style> </style>