CURL - pobieranie pliku na PC

0

Mam link do downloadu pliku w sieci, załóżmy: http://strona.pl/pliki/moj_plik.avi
Chcę za pośrednictwem CURLa pobrać ten plik, ale bezpośrednio na mój komputer, nie na serwer, gdzie znajduje się skrypt.
Jest to wykonalne? Myślałem o jakimś javascripcie typu: window.location albo nagłówki w ten sposób:

Content-Disposition: attachment bla bla

tyle, że jako nazwę pliku musiałbym podać adres URL, a to chyba raczej działać nie będzie.
Może mi ktoś doradzić? Chodzi o to, aby wejście w ten url zostało zainicjowane przez mój serwer, ale już odpowiedź w postaci okienka z downloadem pliku ma pójść bezpośrednio na PC.

0

http://stackoverflow.com/questions/4054618/how-do-i-use-my-server-as-a-proxy-to-download-files-via-php

<font size="5" color="red">BARDZO WAŻNE!!!</span>

If the file is larger than a few megabytes, use fopen fread and frwrite download the file in chunks and send to the client in chunks.

Bez tego zarżniesz serwer.

0

Właśnie sam wpadłem już na to rozwiązanie i zatrzymałem się na kwestii - co w przypadku, gdy plik będzie miał dużą wagę?
Trochę nie rozumiem tej kwestii z fopen, fread, fwrite. Mam ten plik wtedy podzielić na kawałki i zapisać go u siebie na serwerze, po czym wysłać go do przeglądarki?

0

Chyba już wiem co miałeś na myśli: http://stackoverflow.com/questions/14848933/read-and-parse-contents-of-very-large-file?answertab=active#tab-top
Problem jest jednak taki, że ja nie mogę pobrać za pomocą fopen tej zawartości z tego względu, że ja muszę przy wejściu pod podany adres URL przekazać cookiesy (użytkownik wchodzący pod ten adres URL musi być zalogowany). Obecnie robię to przez CURLa.
W przypadku fopen - nie bardzo wiem jakbym mógł tego dokonać :/

0

Mój kod:

$opts = array(
  'http'=>array(
    'header'=>"Cookie: PHPSESSID=".$phpSesSid)
);

$context = stream_context_create($opts);
$start = time();
$handle = fopen($dwn, "r", false, $context);
if ($handle) {
    while (($buffer = fread($handle, 4096)) !== false) {
    }
    fclose($handle);
}

W efekcie, przy pliku ważącym 11MB operacja ta trwała ponad 150 sekund, aż w końcu dostałem " Maximum execution time of 150 seconds exceeded (...)".
Przy pobieraniu tego za pomocą CURLa, trwało to może 4-5 sekund. Trochę mnie to martwi bo finalnie chcę obrabiać pliku ważące grubo ponad 1GB.

Masz jakiś pomysł na to?

0

kod wygląda ok.

pytanie - czy działa na jakimkolwiek pliku? czy na każdym nie?

masz tu jeszcze wersję na fsockopen (miałem to proponować od razu, ale z racji, że musisz sam stworzyć CAŁE żądanie http - wolałem podać info o kontekście do fopen):

$host = "http://rpc.pingomatic.com/";
$path = "";

$httpReq  = "POST /" . $path . " HTTP/1.0\r\n";
$httpReq .= "User-Agent: My Lovely CMS\r\n";
$httpReq .= "Host: " . $host . "\r\n";
$httpReq .= "Content-Type: text/xml\r\n";
$httpReq .= "Content-length: $xmlrpcLength\r\n\r\n";
$httpReq .= "$xmlrpcReq\r\n";   

if ($pinghandle = fsockopen($host, 80)) {
    fputs($pinghandle, $httpReq);
    while (!feof($pinghandle)) { 
        $pingresponse = fgets($pinghandle, 128);
    }
    fclose($pinghandle);
}

pozmieniaj sobie i zobacz czy ruszy

0

kod:

$path = "";

$httpReq  = "POST /" . $path . " HTTP/1.0\r\n";
$httpReq .= "Cookie: PHPSESSID=".$phpSesSid[6];   
 
if ($pinghandle = fsockopen($dwn, 80)) {
    fputs($pinghandle, $httpReq);
    while (!feof($pinghandle)) { 
        $pingresponse = fgets($pinghandle, 128);
		echo $pingresponse.'<br><br>';
    }
    fclose($pinghandle);
}

Warning: fsockopen() [function.fsockopen]: unable to connect to http://strona.pl/plik/plik.doc:80 (Unable to find the socket transport "http" - did you forget to enable it when you configured PHP?) in /home/

Błąd jest z mojej winy? Jako pierwszy parametr w funkcji podałem bezpośredni link do pliku.

0

Zobacz sobie z czego składa się zapytanie HTTP:

http://pl.wikipedia.org/wiki/Hypertext_Transfer_Protocol

0

Nie potrafię sobie z tym poradzić. Obecnie mam tak:

$host = "http://strona.pl/";
$path = str_replace($host, "", $dwn);
 
$httpReq  = "POST /" . $path . " HTTP/1.0\r\n";
$httpReq .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.1.2) Gecko/20090729 desktopsmiley_2_2_5643778701369665_44_71 DS_gamingharbor Firefox/3.5.2 (.NET CLR 3.5.30729)\r\n";
$httpReq .= "Host: " . $host . "\r\n";
$httpReq .= "Content-Type: text/xml\r\n";
 
if ($pinghandle = fsockopen($host, 80)) {
    fputs($pinghandle, $httpReq);
    while (!feof($pinghandle)) { 
        $pingresponse .= fgets($pinghandle, 128);
    }
    fclose($pinghandle);
}

jako host podałem główną ścieżkę do strony, jako path - URI, np. /download/plik.docx

Nagłówki skopiowałem mniej więcej od Ciebie, poza dwoma ostatnimi - wstawiłeś tam jakieś zmienne i nie wiem kompletnie czym je podmienić. W podesłanym przez Ciebie linku nie ma informacji na temat content-length oraz o tym ostatnim parametrze, który u Ciebie również występuje w postaci jakiejś zmiennej.

Przy użyciu powyższego kodu nadal dostaję ten sam błąd. Możesz mnie nakierować co jest nie tak?

0

Przyjrzyj się nagłówkowi Host:, porównaj ze specyfikacją. Tu masz błąd.

Content-Length definiuje długość tego, co wyślesz potem jako dane POST. Przed danymi POST wstawiasz dwa \r\n, następnie wpisujesz dane tak samo jak przy parametrach GET w URI, tj: zmienna=wartosc&druga=wartosc.

Przykładowe zapytanie POST podglądniesz sobie przy użyciu dowolnej przeglądarki ;)
Tak wygląda np. logowanie do nk.pl (dopisałem tylko zmienne GET przy URI, żeby była jasność)

POST /login?dodatkowe=zmienne&dwa=2 HTTP/1.1
User-Agent: Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.17
Host: nk.pl
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en,pl-PL;q=0.9,pl;q=0.8
Accept-Encoding: gzip, deflate
Referer: http://nk.pl/
Cookie: nk_session=5-fPzfP9VxKCUTiL3mSjiPa; basic_auth=54bd599c0ba5592a5e3; nkd=11|VfK; js_enabled=1; nk_window=focused
Connection: Keep-Alive
Content-Length: 80
DNT: 1
Content-Type: application/x-www-form-urlencoded

form_name=login_form&target=&login=dzekowy_login&password=dzekowe_haslo&manual=1
0

OK, mam. Tylko znów pojawił mi się problem z przekierowaniem:

HTTP/1.1 302 Moved Temporarily Server: nginx Date: Mon, 12 Jan 2015 1958 GMT Content-Type: text/html Transfer-Encoding: chunked Connection: keep-alive X-Powered-By: PHP/5.3.28-1~dotdeb.0 Location: http://s2.strona.pl//plik/CS/13724283/35984/ang.docx?s=4 0

z tego co czytam w necie to ta funkcja nie ma czegoś takiego jak followlocation, ale z tego co mi wiadomo to file_get_contents() też tego nie posiada, a tam podając ten adres URL - wszystko działa.

host u mnie wygląda tak: filebit.pl
path wygląda tak: plik/CS/13724529/35984/ang.docx

0

Domyślne file_get_contents podąża za Location
http://stackoverflow.com/questions/6009284/how-do-i-ignore-a-moved-header-with-file-get-contents-in-php

A generalnie to sam musisz napisać parser do tego - analizujesz czy masz przekierowanie w nagłówkach (w odpowiedzi nagłówki od treści będą rozdzielone podwójnym \r\n - pamiętaj, żeby NIE analizować całości oczywiście (kilku GB pliku) - wczytuj kawałek, sprawdź czy skończyły się już nagłówki i wtedy analizuj część nagłókową [zapamiętaj sobie ewentualny początek treści - gdy się okaże, że przekierowania nie ma to prześlij userowi ten początek i potem resztę treści]).

Jeżeli Location występuje no to podążasz za tym (tam mogą być kolejne Location więc jakaś rekurencyjna funkcja się przyda ;)).

Podążając za Location nie powtarzasz POST-a, więc sprawa jest raczej formalnością [ gdyby trzeba było powtarzać POST to wtedy niemożliwym byłoby używanie tego mechanizmu: http://en.wikipedia.org/wiki/Post/Redirect/Get ].

BTW: HTTP to fajny protokół, nie? :) W wolnej chwili polecam pełną specyfikację [a konkretniej RFC].
Szkoda, ze nauki webmasteringu nie zaczyna się od nauki protokołu, na którym działa przecież web.

0

Po prostu ja nigdy nie korzystałem z tych funkcji bo zawsze wystarczał mi albo curl albo file_get_contents. Pierwszy raz spotykam się z wykorzystaniem tych funkcji w taki sposób. Większość błędów popełniam sam i wyżej też moja głupota - tam nie ma takiego hosta: strona.pl tylko s2.strona.pl.

Pełny link wygląda tak: http://s5.filebit.pl/plik/CS/13726274/35984/ang.docx
Po wejściu przez przeglądarkę (manualnie wpisując link), jest ok.

Obecnie mój kod prezentuje się w ten sposób:

$httpReq  = "POST /plik/CS/13726274/35984/ang.docx HTTP/1.1\r\n";
$httpReq  .= "Accept: 	application/json, text/javascript, */*; q=0.01\r\n";
$httpReq  .= "Accept-Encoding: gzip, deflate\r\n";
$httpReq  .= "Accept-Language: pl,en-US;q=0.7,en;q=0.3\r\n";
$httpReq  .= "Host: s5.filebit.pl\r\n";
$httpReq .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.1.2) Gecko/20090729 desktopsmiley_2_2_5643778701369665_44_71 DS_gamingharbor Firefox/3.5.2 (.NET CLR 3.5.30729)\r\n";
$httpReq .= "Host: " . $host . "\r\n";
$httpReq .= "Cookie: PHPSESSID=" . $phpSesSid . "\r\n";
$httpReq .= "Content-Type: application/octet-stream\r\n";
$httpReq .= "Content-Disposition: attachment; filename=\"".$filename[1]."\"\r\n\r\n";
 
if ($pinghandle = fsockopen($host, 80)) {
    fputs($pinghandle, $httpReq);
    while (!feof($pinghandle)) { 
        $pingresponse .= fgets($pinghandle, 128);
    }
    fclose($pinghandle);
}

echo $pingresponse;

Teraz znów dostaję: HTTP/1.1 405 Not Allowed

Mam nadzieję, że jeśli mi się uda coś z tego wreszcie posklejać (coś działającego) to rzeczywiście nie zarżnie mi to serwera i będzie to w miarę sprawnie działało :(

0

Klikając w przeglądarce wysyłasz żądanie "GET", nie "POST"

Czemu tego pliku po prostu nie wgrasz na swój serwer? W powyższy sposób transfer będzie Ci się na serwerze zżerał podwójnie (download + upload)

0

@śmieszna_sprawa - a po co te Content-Disposition WYSYŁASZ do serwera żądając pliku?

Ten nagłówek to ty masz zwrócić do klienta, kiedy to klient żąda go od Ciebie.
Mówiliśmy o podążaniu za redirectami, a Ty nagle doklejasz coś, co nie ma związku z logicznym ciągiem tego wątku. Dlaczego?

0

Udało mi się to poskładać wreszcie, ale wynik nie jest zadowalający. 11MB-ajtowy plik "obrabia się" ponad minutę.
Nie da się jakoś przekazać tego żądania dot. pobrania pliku bezpośrednio do przeglądarki, nie angażując w to w ogóle serwera? Może jakoś za pomocą javascriptu by się dało, zachowując odpowiednie cookies?

0

Nie wymusisz na przeglądarce ustawienie odpowiednich cookies dla innej domeny - byłoby to naruszenie bezpieczeństwa.

Możesz sobić zwykłe przekierowanie, ale cookiesy będą takie, jak ktoś ma lokalnie.

Wrzuć cały kod (tylko niestety - bez zaciemniania, i tak już powiedziałeś, że chodzi o filebit, a bez możliwości uruchomienia tego - nie będę mógł zweryfikować gdzie leży błąd) - poszukam przyczyny długiego wykonywania.

0

Słuchaj, udało mi się z tym rozwiązaniem:

$context = stream_context_create($opts);
$handle = fopen($dwn, "r", false, $context);
if ($handle) {
    while (($buffer = fread($handle, 4096)) !== false)
	{
		echo $buffer;
	}
    fclose($handle);
}

I działa elegancko, plik 1,2 GB przerabia w 3-4 sekundy, takze jest pięknie.
Jednak coś się dzieje dziwnego bo wyskakuje mi powiadomienie o pobieraniu pliku, ściąga się wszystko elegancko, aż gdy dojdzie do mniej więcej 120MB pobierania i dostaję informację: "Pobieranie pliku nie powiodło się".

To już drugi plik, gdzie takie coś dostałem. O czym to może świadczyć? O tym, że ta pętla po prostu za wcześnie się "kończy" i nie przekazuje całego pliku do widoku i przeglądarka pobiera mi tylko część?

Druga sprawa - jak za pomocą powyższego rozwiązania sprawdzić i przekazać do nagłówka wielkość pobieranego pliku?

0

po 120MB zapychasz całą pamięć i się wywala :p ob_flush() bodajże (poczytaj o funkcjach ob)

0

http://funkcje.net/view/3/551/index.html

flush () nie ma wpływu na system buforowania serwera internetowego lub przeglądarkę po stronie klienta. Tak więc musimy połączyć obie ob_flush() i flush(), aby opróżnić wyjściowe bufory.

Zrobiłem więc tak:

$context = stream_context_create($opts);
$handle = fopen($dwn, "r", false, $context);
if ($handle)
{
    while (!feof($handle))
	{
        $buffer = fgets($handle, 4096);
		echo $buffer;
		ob_flush();
		flush();
	}
    fclose($handle);
}

Ale nadal przerywa ściąganie ;/

0

http://funkcje.net/view/3/551/index.html

flush () nie ma wpływu na system buforowania serwera internetowego lub przeglądarkę po stronie klienta. Tak więc musimy połączyć obie ob_flush() i flush(), aby opróżnić wyjściowe bufory.

Zrobiłem więc tak:

$context = stream_context_create($opts);
$handle = fopen($dwn, "r", false, $context);
if ($handle)
{
    while (!feof($handle))
	{
        $buffer = fgets($handle, 4096);
		echo $buffer;
		ob_flush();
		flush();
	}
    fclose($handle);
}

Ale nadal przerywa ściąganie ;/

0

zajrzyj do logów błędów (no bo przecież logujesz błędy, no nie?)

0

Tak wyglądają te błędy:

MOJE_IP - [17/Jan/201556:30 +0100] "GET /tester.php HTTP/1.1" 404 56689429 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0"

0

To jest access log, Ciebie interesuje error log.

0

OK, mam. Są trzy błędy:

[Sat Jan 17 1209 2015] [warn] [client 178.183.131.38] (104)Connection reset by peer: mod_fcgid: error reading data from FastCGI server
[Sat Jan 17 1209 2015] [warn] [client 178.183.131.38] (104)Connection reset by peer: mod_fcgid: ap_pass_brigade failed in handle_request_ipc function
[Sat Jan 17 1209 2015] [error] [client 178.183.131.38] File does not exist: /home/name/domains/name.yyy.pl/public_html/500.shtml

0

niewiele to mówi :/ spróbuj otworzyć ten urwany plik w hexedytorze i zainteresuj się ostatnimi bajtami - php możliwe, że doklei tam jakiś swój błąd

0

Możesz powiedzieć w jakim konkretnie programie to otworzyć? W notepad++ są same krzaki bo to plik .avi.

0

google: hex editor

cokolwiek, co pozwoli Ci na odczytanie ostatnich znaków z pliku

0

Nic nie widzę niepokojącego po rozkodowaniu, żadnego błędu.

A może po prostu wyechuję sobie na ekran ten plik i zobaczę co się stanie w trakcie przelotów przez pętlę. Może rzuci mi na ekran jakimś błędem?

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