Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [PHP] cURL / fsockopen - jak odczytać pobraną ilość danych na żywo ?
vimoco
post 12.08.2012, 23:25:49
Post #1





Grupa: Zarejestrowani
Postów: 21
Pomógł: 0
Dołączył: 23.07.2009

Ostrzeżenie: (0%)
-----


Witka!

Mam pytanie do Was chłopaki, gdyż chciałbym zliczyć na żywo ile użytkownik mojej strony pobrał danych pliku.
Przykładowo pobiera 100 mb plik, gdy przerwie na np. 33 mb to chce mieć zapisane w MySQL / pliku, także jeżeli dalej będzie pobierałi dokończy to żeby całą wage pliku dopisało.

Pliki podaje poprzez header + cURL lub fsockopen + stream_get_line

Przy cURL probowałem z WRITEFUNCTION, jednak że ona działa poprawnie ale tylko przy pobieraniu przez przeglądarkę np. taki dodatek FDM (Free Download Manager) czy też IDM (Internet Download Manager) to wszystko psuje, i wyświetla / zapisuje błędne wyniki.

taka funkcja:
  1. function zapiszRozmiar($handle, $content){
  2. $lenght = strlen($content);
  3. file_put_contents("pobrano", file_get_contents("pobrano") + $lenght);
  4. echo $content;
  5. return $lenght;
  6. }


dopisek do cURL:
  1. curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'zapiszRozmiar');


Tak samo dzieje się przy fsockopen, gdy zastosuje taki kod:
  1. while (!feof($fp) && (connection_status()==0)) {
  2. $recv = @stream_get_line($fp, 1024);
  3. file_put_contents("pobrano", file_get_contents("bytesDownload") + strlen($recv));
  4. @print $recv;
  5. @flush();
  6. }


Również przy akceleatorze FDM / IDM zwraca błędne wyniki np. pobranie 100 MB pokazuje 9, 12, 33 megajbaty pobrane.

Ma ktoś jakąś ideę ?

Dzięki z góry.
Pozdrawiam,

Ten post edytował vimoco 12.08.2012, 23:28:08
Go to the top of the page
+Quote Post
Sephirus
post 13.08.2012, 07:58:05
Post #2





Grupa: Zarejestrowani
Postów: 1 527
Pomógł: 438
Dołączył: 28.06.2011
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Pobierając jakimś managerem typy IDM czy FDM tworzysz więcej niż jedną sesje pobierania pliku. W związku z tym do twojego pliku gdzie zapisujesz ile pobrano nadpisują się dane z różnych sesji. Manager pobiera plik częściami zatem nie rozróżniając sesji nadpisujesz ten sam plik. Przed odpaleniem pobierania ustal jakąś zmienną globalną:

  1. $nazwaPliku = md5(uniqid());


a w funkcji od WRITE_FUNCTION daj:

  1. function zapiszRozmiar($handle, $content){
  2. $lenght = strlen($content);
  3. file_put_contents("pobrano_".$nazwaPliku, file_get_contents("pobrano".$nazwaPliku) + $lenght);
  4. echo $content;
  5. return $lenght;
  6. }


Ogólnie ta metoda zapisywania jest mało wydajna przez odczyt/zapis pliku przy każdorazowym pobraniu jego cząstki - zmieniłbym to po prostu na filesize() od pliku docelowego - zapisz gdzieś ile ma pobierany plik jednorazowo - może być to w pliku. Ile się aktualnie pobrało odczytasz odpalając skrypt sprawdzający wielkość pliku docelowego a dzieląc ten rozmiar przez rozmiar całego masz procent pobrania.

HTH wink.gif

EDIT:

Dodatkowo zamiast strlen używaj mb_strlen wink.gif

Ten post edytował Sephirus 13.08.2012, 07:59:18


--------------------
If you're good at something, never do it for free.
Potrzebujesz skryptu JS lub PHP - szukasz kogoś kto przetestuje twoją aplikację pod względem bezpieczeństwa? Szybko i solidnie? Napisz ;)
Mój blog - Jak zwiększyć wydajność front-endu - O buforowaniu wyjścia w PHP słów kilka...
Go to the top of the page
+Quote Post
wNogachSpisz
post 13.08.2012, 10:06:57
Post #3





Grupa: Zarejestrowani
Postów: 1 233
Pomógł: 87
Dołączył: 6.03.2009

Ostrzeżenie: (40%)
XX---


Pytanie 1.
Czy chcesz aktualizować licznik kiedy trwa pobieranie?
Przykładowo, user w chwili #1 ma pobranych 0MB, w chwili #2 99MB i właśnie kończy pobiernie pliku.
Czy chcesz mieć w chwili #2 na stronie 99MB czy przebolejesz jeśli będzie 0 MB i poczekasz z aktualizacją bazy aż pobieranie się zakończy lub przerwie.
Go to the top of the page
+Quote Post
vimoco
post 16.08.2012, 03:24:27
Post #4





Grupa: Zarejestrowani
Postów: 21
Pomógł: 0
Dołączył: 23.07.2009

Ostrzeżenie: (0%)
-----


Cytat(wNogachSpisz @ 13.08.2012, 11:06:57 ) *
Pytanie 1.
Czy chcesz aktualizować licznik kiedy trwa pobieranie?
Przykładowo, user w chwili #1 ma pobranych 0MB, w chwili #2 99MB i właśnie kończy pobiernie pliku.
Czy chcesz mieć w chwili #2 na stronie 99MB czy przebolejesz jeśli będzie 0 MB i poczekasz z aktualizacją bazy aż pobieranie się zakończy lub przerwie.

Chce aktualizować kiedy trwa pobieranie, po to że przykładowo głupim rozwiązaniem było by jeżeli ktoś uruchomi pobieranie i anuluje a zliczy jako pełne pobranie, albo odpali 8 połączeń i mu zliczę 8 razy, albo jeszcze inaczej że pobierze 4 razy ten sam plik a zliczy tylko jako pojedyncze pobranie.

Chce na "żywo" aktualizować ile jest pobrane, jeżeli nie pełne to ma zapisać tyle ile zostało pobrane.

Cytat(Sephirus @ 13.08.2012, 08:58:05 ) *
Pobierając jakimś managerem typy IDM czy FDM tworzysz więcej niż jedną sesje pobierania pliku. W związku z tym do twojego pliku gdzie zapisujesz ile pobrano nadpisują się dane z różnych sesji. Manager pobiera plik częściami zatem nie rozróżniając sesji nadpisujesz ten sam plik. Przed odpaleniem pobierania ustal jakąś zmienną globalną:

  1. $nazwaPliku = md5(uniqid());


a w funkcji od WRITE_FUNCTION daj:

  1. function zapiszRozmiar($handle, $content){
  2. $lenght = strlen($content);
  3. file_put_contents("pobrano_".$nazwaPliku, file_get_contents("pobrano".$nazwaPliku) + $lenght);
  4. echo $content;
  5. return $lenght;
  6. }


Ogólnie ta metoda zapisywania jest mało wydajna przez odczyt/zapis pliku przy każdorazowym pobraniu jego cząstki - zmieniłbym to po prostu na filesize() od pliku docelowego - zapisz gdzieś ile ma pobierany plik jednorazowo - może być to w pliku. Ile się aktualnie pobrało odczytasz odpalając skrypt sprawdzający wielkość pliku docelowego a dzieląc ten rozmiar przez rozmiar całego masz procent pobrania.

HTH wink.gif

EDIT:

Dodatkowo zamiast strlen używaj mb_strlen wink.gif

niestety nie zbyt to działa.. pobrałem 100 MB akceleratorem IDM, stworzyło 23 takich plików z zapisaną liczbą i suma ich wynosi: 307393
także ma to się nijak do prawdziwej wielkości 100 MB
takie wartosci miałem wypisane w plikach: http://wklej.to/2ufNP

filesize? tak jak pisałem wyżej nie chce zliczać od razu pełnego pliku, chce wiedzieć jeżeli pobrał 30 mb, to mam mieć te 30 mb, także filesize tutaj się nie spisze.

Ma ktoś jakiś pomysł ? Na pewno jest to możliwe, ale nie mam pojęcia jak.
Go to the top of the page
+Quote Post
wNogachSpisz
post 18.08.2012, 11:30:18
Post #5





Grupa: Zarejestrowani
Postów: 1 233
Pomógł: 87
Dołączył: 6.03.2009

Ostrzeżenie: (40%)
XX---


Nie rozumiemy się.
Pytam czy z aktualizacją można poczekać aż do zakończenia lub przerwania pobierania.

Jeśli nie, to pojawia się pytanie: Co ile przesłanych bajtów aktualizować licznik.
Go to the top of the page
+Quote Post
vimoco
post 19.08.2012, 19:09:47
Post #6





Grupa: Zarejestrowani
Postów: 21
Pomógł: 0
Dołączył: 23.07.2009

Ostrzeżenie: (0%)
-----


Cytat(wNogachSpisz @ 18.08.2012, 12:30:18 ) *
Nie rozumiemy się.
Pytam czy z aktualizacją można poczekać aż do zakończenia lub przerwania pobierania.

Jeśli nie, to pojawia się pytanie: Co ile przesłanych bajtów aktualizować licznik.

Wolałbym nie czekać do zakończenia lub przerwania pobierania gdyż wtedy można by było abusować system, odpalając kilkanascie plików, i potem wynik byłby na minusie zapewne.

Myślę że co 1 MB wystarczy czyli (1000000 bajtów)
Go to the top of the page
+Quote Post
wNogachSpisz
post 19.08.2012, 19:48:08
Post #7





Grupa: Zarejestrowani
Postów: 1 233
Pomógł: 87
Dołączył: 6.03.2009

Ostrzeżenie: (40%)
XX---


OK. Zatem jedziemy:

1. Opłaca się skorzystasz z biblioteki, która kompleksowo obsłuży pobieranie pliku, to zagwarantuje, że żaden szczegół nie zostanie pozostawiony przypadkowi. Mowie oczywiście o PEAR:HTTP_Download. Nie wspomnę o całej masie przydantych opcji jak zarządzanie cachowaniem czy ograniczanie prędkości pobierania.

2. Przy pomocy funkcji „stream_wrapper_register” definiujesz własną klasę do obsługi strumieni tzw. „stream wrapper”. Opis jak to zrobić znajduje się tutaj

3. Powiązujesz stream wrapper z obiektem PEAR:HTTP_Download
przy pomocy metody: HTTP_Download::setResource

Teraz najważniejsze.
Twój stream wrapper musi w metodzie „stream_read()” podnosić licznik danych odczytanych z uchwytu pliku oraz sprawdzać czy ten licznik przekroczył 1MB. Jeśli przekroczył, aktualizujesz bazę. Wszystkie uchwyty do bazy możesz otworzyć i zamknąć wewnątrz obiektu stream wrapper.

Jarzysz?

// Edit
Dodatkowo aktualizujesz bazę w metodzie stream_close(), tak żeby nie dało się omijać licznika sztuczką polegającą na opalalaniu zapytań http-range z którkim zakresem bajtów, na co cierpi co drugi hosting plików happy.gif.

Ideał to event typu "chunkSended" emitowany przez HTTP_Downlad, pod który podpinamy się z listenerem podnoszącym licznik, niestety nic takiego nie jest dostępne.

Ten post edytował wNogachSpisz 19.08.2012, 20:31:56
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 14.08.2025 - 08:17