PHP upload – pasek postępu

Temat co jakiś czas wraca w dyskusjach i przez niektórych uznawany jest za trudny. Nic bardziej mylnego, sprawę można zamknąć w kilku linijkach kodu.

Ostatnio zetknąłem się z integrację aplikacji z API, które oferuje jeden z dostawców „chmur”. Dość specyficznie obsługują upload, oferując tak naprawdę tylko przesył danych (POST), bez zapewnienia dodatkowych możliwości.

Jeśli użyjemy do tego CURL-a, kilka funkcji możemy uzyskać sami. Jedną z takich funkcji jest chociażby stan postępu wgrywania pliku. CURL jest biblioteką napisaną w C, dzięki temu możemy skorzystać np. z wywołania zwrotnego, który wygląda w oryginale tak:

typedef int (*curl_progress_callback)(void *clientp,
                                      double dltotal,
                                      double dlnow,
                                      double ultotal,
                                      double ulnow);

W takim wypadku definiujemy na jego wzór własną funkcję zwrotną. W najprostszej postaci może wyglądać tak:

function progress($clientp, $dltotal, $dlnow, $ultotal, $ulnow) {
    if ($ulnow > 0) {
        echo round($ulnow / $ultotal * 100, 2) . PHP_EOL;
    }
}

Pozostaje już tylko użyć tej funkcji w naszym wywołaniu CURL-a:

$args = array();
$args['SourceFile_1'] = new CurlFile('plik.jpg', 'application/octet-stream', 'plik.jpg');

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $args);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progress');
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
$response = curl_exec($ch);

Oczywiście w prawdziwym przypadku musimy jeszcze zaiinicjować $ch, zalogować się lub ustawić odpowiednie nagłówki uwierzytelniające, oraz odpowiednio zdefiniować zwrotkę z funkcji progress, aby móc to odebrać jako np. JSON w przeglądarce. A resztą zajme się już człowiek od frontendu ;)

  • nospor

    Sadzilem, ze bedzie tu mowa o upload przez forma w przegladarce, a to co tu pokazales sprowadza się do uploadu przez serwer na inny serwer, tak?