Jak zainicjować pobieranie pliku?

0

Witam serdecznie!

Jestem tutaj nowy i chciałem się serdecznie przywitać z wszystkimi.

Moja przygoda z PHP rozpoczęła się nie dawno i mam mały problem z przesłaniem pliku z serwera do użytkownika i proszę o pomoc w rozwiązaniu tego problemu.

Mam taką funkcję przysyłania pliku:

function sendFileToUser($filename_, $filepath_)
{
    if (!file_exists($filepath_)) {
        die("Plik nie istnieje.");
    }
    else
    {	
    header('Content-Type: application/octet-stream');
    header('Content-Description: File Transfer');
    header("Content-Disposition: attachment; filename=\"" . $filename_ . "\"");
    header("Content-Transfer-Encoding: binary");
    header('Content-Length:' . filesize($filepath_));
    ob_clean();
    flush();
    readfile($filepath_);
    exit;
    }
}

I później gdzieś dalej wywołanie tej funkcji i przesłanie na stronę główną informacji poprzez JSON o przesyłaniu pliku:

if(isset($datatab)){
    $writefile = fopen($file_name_out, "w");
    fwrite($writefile, $tabwrite,512);							//zapisuje w folderze serwera obrobiony plik o nazwie $file_name_out
    fclose($writefile);
    //wysyłam plik do urzytkownika
    sendFileToUser($file_name_out, $send_file);
    echo '<script language="javascript" type="text/javascript">window.top.window.viewText(' . json_encode("Wysyłam plik do użytkownika!") . ');</script>';
}

No i właśnie nie wysyła mi się informacja na stronę główną (plik wysyła się bez problemu):

echo '<script language="javascript" type="text/javascript">window.top.window.viewText(' . json_encode("Wysyłam plik do użytkownika!") . ');</script>';

Jeśli wykasuję funkcję sendFileToUser z listingu to normalnie wyświetla informację.

0

A po co tam jest ten exit;? On przypadkiem Ci nie ubija skryptu?

0

Po usunięciu exit; nic się nie zmieniło.

0
nikitis napisał(a):

Po usunięciu exit; nic się nie zmieniło.

Pokaż cały kod jaki masz.

0
<?php

	session_start();
	//funkcja wysyłająca plik z powrotem do kompa
	function sendFileToUser($filename_, $filepath_)
	{
		if (!file_exists($filepath_)) {
			die("Plik nie istnieje.");
		}
		else
		{	
		header('Content-Type: application/octet-stream');
		header('Content-Description: File Transfer');
		header("Content-Disposition: attachment; filename=\"" . $filename_ . "\"");
		header("Content-Transfer-Encoding: binary");
		header('Content-Length:' . filesize($filepath_));
		ob_clean();
		flush();
		readfile($filepath_);
		}
	}


	//sciezka ladowanych plikow immo
	chdir('../../../tmpfile/immo');								//ustala bierzący roboczy katalog
	$destination_path = getcwd().DIRECTORY_SEPARATOR;			//do zmiennej $destination_path przypisuje ścieżkę roboczą z separatorami bez nazwy pliku, tylko katalog
	$result = array('success'=>0);								//tworzy tablice rezultatu operacji z jednym polem "success' równy 0
	$file_name = basename( $_FILES['myfile']['name']);			//oryginalna nazwa pliku pobrana z formularza "myfile"
	$explode_name = explode('.',$file_name);					//rozdziela nazwę pliku separatorem "." i zapisuje poszczególen części do tablicy
	//dodanie daty do pliku
	$data = date('H_i_s_d_m_Y');								//pobiera aktualną datę i czas
	$new_file_name = $explode_name[0] . '(' . $data . ').' . $explode_name[1]; //dodaje do nazwy pliku datę
	$_SESSION['filename'] = $new_file_name;						//zmienia zawartość zmiennej sesyjnej "filename" na nową nazwę pliku z datą
	$target_path = $destination_path . $new_file_name;			//tworzy nazwę pliku z datą
	if(@move_uploaded_file($_FILES['myfile']['tmp_name'], $target_path)) //zapisuje pobrany plik z datą
	{
		$result['success'] = 1;
        $result['fileInfo'] = $target_path;
	}
	
	//nazwa pliku do wysłania pliku poprawionego
	$file_name_out= $explode_name[0]."(immo off by docAuto).bin";
	//otwieranie pliku do interpretacji
	$workfile = $target_path;
	$workf = fopen($workfile, "r") or die ('<script language="javascript" type="text/javascript">window.top.window.viewText(' . json_encode("Can't open file") . ');</script>');
	$i=0;
	while(!feof($workf)){
		$datatab[$i++] = fgetc($workf);
	}
	if($workf){
		fclose($workf);
	}
	$send_file = $destination_path . $file_name_out;
	$datatabsize = sizeof($datatab);
	
	//ładowanie pliku algorytmu w zależności od zmiennej sessyjnej: "sterownik"
	//tablica danych w zaminnej: $datatab;
	//wielkość tablicy w zmiennej
	
	if(isset($datatab)){
		$writefile = fopen($file_name_out, "w");
		fwrite($writefile, $tabwrite,512);							//zapisuje w folderze serwera obrobiony plik o nazwie $file_name_out
		fclose($writefile);
		//wysyłam plik do urzytkownika
		sendFileToUser($file_name_out, $send_file);
		echo '<script language="javascript" type="text/javascript">window.top.window.viewText(' . json_encode("Wysyłam plik do użytkownika!") . ');</script>';
	}	
?>
0
nikitis napisał(a):

No i właśnie nie wysyła mi się informacja na stronę główną (plik wysyła się bez problemu):

echo '<script language="javascript" type="text/javascript">window.top.window.viewText(' . json_encode("Wysyłam plik do użytkownika!") . ');</script>';

Jeśli wykasuję funkcję sendFileToUser z listingu to normalnie wyświetla informację.

Próbujesz zrobić dwie rzeczy na raz.

  1. Otwórz narzędzia developerskie w przeglądarce (np. Prawy Klawisz > Zbadaj) i wybierz zakładkę Network:
    screenshot-20231227094319.png
  2. Ściągnij plik
  3. W narzędziach developerskich powinieneś zobaczyć żądanie do Twojej strony która pobierze plik
  4. Kliknij je
  5. Wybierz "Response" screenshot-20231227094420.png
  6. Zobacz co tak na prawdę zwrócił Twój skrypt
0

Nic nie zwrócił, napisał:

Failed to load response data: No resource with given identifier found.

A powiedz mi wiesz jak rozwiązać ten problem?

0

W tej funkcji sendFileToUser masz użycie flash i ob_clean() ale nie masz ob_start. Nie wiadomo co jest w tym buforze i co pachasz do przeglądarki.
IMHO trochę za prosto chcesz to wszystko zrobić.
Zobacz. Otrzymujesz binarke od użytkownika. Przy jej otworzeniu może dziać się wiele, może to też potrwać dłużej niż kilka sekund. Potem modyfikacja i zapis. Tu znów może dziać się wiele, od braku miejsca na dysku, po timeout, bo przesłany plik był np. za duży.
Teraz dopiero ostatnie wysyłka do przeglądarki.
Wydaje mi się, że lepiej byłoby to wszystko porozbijać i użyć Ajax do komunikacji.
Zobacz sobie jak z użyciem Ajax przestać plik z i do przeglądarki, a w PHP rób beckendowe rzeczy jak sam zapis, modyfikacja itd.

2
nikitis napisał(a):

Nic nie zwrócił, napisał:

Failed to load response data: No resource with given identifier found.

A powiedz mi wiesz jak rozwiązać ten problem?

Próbujesz wyświetlić stronę oraz plik jednocześnie, a tak się nie da.

Powinieneś mieć dwa wywołania strony: jeden z informacją, jeden z plikiem.

0

ok dziękuję za podpowiedź, podziałam z tym i dam znać jak to zrobiłem.

1

Chyba mnie to przerosło, kombinowałem ale dalej mam z tym problem.

Zrobiłem wywołanie funkcji w javascript ze strony głownej:

echo '<script language="javascript" type="text/javascript">window.top.window.sendfile(' . json_encode($file_name_out) . ',' . json_encode($send_file) . ');</script>';

gdzie funkcja wywołuje skryp do wysyłania pliku:

function sendfile(filename, filepath)
{
    var xxx = "kometa";
    $.ajax({
        type: 'POST', // Metoda przesyłania danych
        url: '/materialy/immo/vag/sendfiletouser.php', // Ścieżka do pliku PHP
        data: {'filename' : filename, 'filepath' : filepath,}, // Dane przesyłane do PHP
        dataType: 'text',
        success: function(response) { // Funkcja wywoływana po pomyślnym przesłaniu danych
            console.log(response); // Wyświetl odpowiedź z PHP w konsoli
    }
    });
}

Wszystko fajnie wywołuje skrypt "sendfiletouser.php" ale nie wysyła pliku do przeglądarki.

sendfiletouser.php

<?php

if (isset($_POST['filename']) && isset($_POST['filepath'])) {
    $filename = $_POST['filename'];
	$filepath = $_POST['filepath'];
	echo $filename;
	echo $filepath;
    // reszta kodu
} 
else {
    echo "Zmienne nie zostały przesłane.";
}

if (!file_exists($filepath)) {
			die("Plik nie istnieje.");
		}
else
		{	
		chdir('../../../tmpfile/immo');
		ob_start();
		header('Content-Type: application/octet-stream');
		header('Content-Description: File Transfer');
		header('Content-Disposition: attachment; filename=' . $filename . '');
		header('Content-Length:' . filesize($filename));
		ob_clean();
		//flush();
		readfile($filename);
		echo "Wysyłam plik do przeglądarki.";
		}
?>
0

Spróbuj tak:

<?php

if (!array_key_exists('filename', $_GET)) {
    http_response_code(400); // bad request
    return;
}

$fileName = $_GET['filename'];
$filePath = getCwd() . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . $fileName;

if (!file_exists($filePath)) {
    http_response_code(404); // not found
    return;
}

header('Content-Type: application/octet-stream');
header('Content-Description: File Transfer');
header("Content-Disposition: attachment; filename=$fileName");
header('Content-Length:' . fileSize($filePath));
readFile($filePath);

Cały projekt w załączniku: nikitis.zip

0

Działa to, u mnie pobieranie też chodziło, ale głównie chodzi mi w skrypcie o to:
Użytkownik wysyła plik na serwer (upload), serwer obrabia ten plik i wysyła go s powrotem do przeglądarki (download), oraz wysyła wiadomość tekstową na główną stronę że obrobił plik poprawnie. Wszystko mi działa oprócz wysłania wiadomości.
Czyli w twoim projekcie potrzebował bym jeszcze aby po pobraniu pliku (dog lub cat) wyświetliła mi się wiadomość na głównej stronie że pobrałem dany plik (wiadomość ta ma być wysłana z plik (download.php)

0
nikitis napisał(a):

Czyli w twoim projekcie potrzebował bym jeszcze aby po pobraniu pliku (dog lub cat) wyświetliła mi się wiadomość na głównej stronie że pobrałem dany plik (wiadomość ta ma być wysłana z plik (download.php)

No to możesz to zrobić na dwa sposoby: albo przez przekierowanie użytkownika na inną stronę z podziękowaniem, albo w JS'ie pokazać komunikat na aktualnej stronie.

0

Najlepiej Javascript ale właśnie nie wiem jak to zrobić, jak przesłać wiadomość z pliku download.php do okna głównego.

0

Przetwarzanie danych mam już zrobione, tylko nie wiem właśnie jak przesłać informację zwrotną.

0
nikitis napisał(a):

Przetwarzanie danych mam już zrobione, tylko nie wiem właśnie jak przesłać informację zwrotną.

A możesz pokazać cały kod?

0

To jest duży projekt, chciał bym to uruchomić na razie na tym co mi pokazałeś żeby z pliku download.php po wysłaniu pliku do przeglądarki zmienić np napis Witaj na Wysłałem.

0
nikitis napisał(a):

To jest duży projekt, chciał bym to uruchomić na razie na tym co mi pokazałeś żeby z pliku download.php po wysłaniu pliku do przeglądarki zmienić np napis Witaj na Wysłałem.

Tylko sposób w jaki to będzie zrobione, zależy od sposobu w jaki przetwarzasz te obrazki.

No bo, generalnie - są dwa sposoby jak mógłbyś to ograć z JS'em.

  • Pierwsze - Albo przetwarzać obraz w momencie requestu (czyli flow: user uploaduje plik, nic się nie dzieje, user prosi o pobranie pliku, teraz serwer zaczyna przetwarzać obraz, serwer daje znać klientowi że gotowe, klient pobiera plik). To jest trochę gorsze podejście, ale łatwiejsze w implementacji?
    • client: upload
    • server: request, process, response
    • client: download
  • Drugie - Albo przetwarzać obraz od razu po upload'zie (czyli flow: user uploaduje plik, serwer od razu zaczna przetwarzanie, wynik przetwarzania jest zapisywany na serwerze, klient czeka na info o skończeniu przetwarzania, klient pobiera zapisany plik). To jest lepsze dla klienta.
    • client: upload,
    • server: process, store
    • client: request, and download

Oba sposoby wymagają innego kodu w kliencie do obsłużenia tego, więc pytanie które Ci bardziej pasuje.

Pierwsze jest wolniejsze i gorsze w użyciu, ale nie zapisuje wyniku na serverze, ale drugie jest lepsze i szybsze dla klienta.

0

Drugie, to ma działać z automatu: klient wysyła plik na serwer, serwer go od razu obrabia i wysyła do klienta bez pytania. ( no i wysyła wiadomość na stronę główną że zrobił i wysłał s powrotem).

0
nikitis napisał(a):

Drugie, to ma działać z automatu: klient wysyła plik na serwer, serwer go od razu obrabia i wysyła do klienta bez pytania. ( no i wysyła wiadomość na stronę główną że zrobił i wysłał s powrotem).

Czyli chcesz żeby upload i download się wykonał za "jednym zamachem"?

No dobra, tylko co jeśli przetworzenie tego obrazu potrwa np 10, 20, 30 sekund? Tyle client ma czekać na response? Niektóre przeglądarki mogą zrobić timeout i przerwać połączenie. Wtedy lipa z takiego podejścia.

Takie podejście za jednym zamachem miałoby sens gdybyś był przekonany że przetworzenie obrazu potrwa mniej niż pół sekundy, bo inaczej to jest bardzo słaby user experience.

Lepszym podejściem byłoby na dwa razy, tzn. osobny request na upload, i osobny na download - tzn. "lepsze" czyli bardziej odporne na długi czas przetwarzania.

0

Tak ma być za jednym zamachem, to będzie krótko trwało, będzie tylko dopisany do obrazka mały element, obrazki też będą małe, max 20kb. Chodzi mi tylko o sam mechanizm jak to zrobić na podstawie krótkiego przykładu.

0
nikitis napisał(a):

Tak ma być za jednym zamachem, to będzie krótko trwało, będzie tylko dopisany do obrazka mały element, obrazki też będą małe, max 20kb. Chodzi mi tylko o sam mechanizm jak to zrobić na podstawie krótkiego przykładu.

No to jeśli nie chcesz zapisywać obrazu na dysku na serwerze, a jednocześnie chcesz dać znać JS'owi że się "udało", to właściwie masz tylko jedno wyjście:

  1. Rozpocznij upload przez JS'a
  2. Serwer przyjmuje plik, przetwarza, odpowiada
  3. JS przechwyuje odpowiedź i plik
  4. JS wyświetla komunikat userowi
  5. JS samo rozpoczyna pobieranie pliku w kliencie

Tylko w sumie pytanie. Ten przetworzony obraz ma się pojawić w przeglądarce usera? Czy ma go od razu pobrać?

Ja napisałem że przetworzony obraz się pokazuje, i jest przycisk "Pobierz", ale łatwo dałoby się zrobić żeby od razu się pobierało.

index.html:

<!DOCTYPE html>
<html lang="pl">
<head>
  <title>Upload image</title>
  <style>
      div#success {
          display: none;
      }

      p#success-text {
          padding: 1rem;
          color: darkgreen;
          border: 1px solid green;
      }

      p#error-text {
          display: none;
          padding: 1rem;
          color: maroon;
          border: 1px solid red;
      }
  </style>
</head>
<body>
<p>Wybierz obraz JPEG:</p>
<form method="POST" action="upload.php" enctype="multipart/form-data">
  <input name="file" type="file"/>
  <p>
    <button>Upload image</button>
  </p>
</form>
<div id="success">
  <p id="success-text"></p>
  <img/>
  <p>
    <a>Pobierz</a>
  </p>
</div>
<p id="error-text"></p>
<script>
  window.addEventListener('load', onLoad);

  function onLoad() {
    const form = window.document.forms[0];
    const fileInput = window.document.getElementsByName("file")[0];

    form.addEventListener('submit', event => {
      event.preventDefault();

      const formData = new FormData();
      formData.append('file', fileInput.files[0]);

      processFile(form.action, formData);
    });
  }

  function processFile(input, formData) {
    fetch(input, {method: 'POST', body: formData})
      .then(response => {
        if (response.status === 200) {
          response.blob()
            .then(result => URL.createObjectURL(result))
            .then(onSuccess);
        }
        if (response.status === 400) {
          response.json().then(onError);
        }
      });
  }

  function onSuccess(imageUrl) {
    const successBox = document.getElementById("success");
    successBox.style.display = 'block';

    const image = successBox.getElementsByTagName("img")[0];
    image.src = imageUrl;

    const text = successBox.getElementsByTagName("p")[0];
    text.innerText = 'Przetworzono obraz';

    const link = successBox.getElementsByTagName('a')[0];
    link.href = imageUrl;
    link.download = 'process file.jpeg';
  }

  function onError(error) {
    const errorText = document.getElementById("error-text");
    errorText.innerText = error.message;
    errorText.style.display = 'block';
  }
</script>
</body>
</html>

upload.php

<?php

function processImageJpeg(string $filePath): void
{
    $image = imageCreateFromJpeg($filePath);
    $colorWhite = imageColorAllocate($image, 255, 255, 255);
    imageString($image, 3, 10, 10, 'This is my sample text', $colorWhite);
    imageJpeg($image);
    imageDestroy($image);
}

function error(string $errorText): void
{
    header('Content-Type: application/json');
    http_response_code(400); // bad request
    echo \json_encode(['message' => $errorText]);
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405); // method not allowed
    return;
}

if (!array_key_exists('file', $_FILES)) {
    error('No file uploaded');
    return;
}

$filePath = $_FILES['file']['tmp_name'];
$fileInfo = getImageSize($filePath);
if ($fileInfo === false) {
    error('Not an image file.');
    return;
}

if ($fileInfo['mime'] !== 'image/jpeg') {
    error('Only JPEG images are supported.');
    return;
}

http_response_code(200);
header('Content-Type: image/jpeg');
processImageJpeg($filePath);

1 użytkowników online, w tym zalogowanych: 0, gości: 1