Zruck zum Blog, du Zniachtl
Mai 2018·2 Min. zum LesnVo da KI übersetzt

HTTP Range Request mit PHP valorbeitn

#downloadmanagement#php#range-request

Manchmoi wolln mia ned die gesamte Datei vom Server lodn, sondern nur an bestimmten Ausschnitt (Range) von da Datei. Mia mechtn also a Startbyte und a Endbyte definiern und olle Daten aus dem Bereich zruckgebn. Des is sinnvoll bei Partial Downloads (= wenn mia an scho begonnenen Downloadvorgang fortsetzn wolln oda a Downloadmanagement via PHP entwickeln wolln) oda a im Bereich vom Videostreaming, wenn mia ned von Anfang an des gesamte Video lodn wolln, sondern nur den relevanten Teil, der als Nächstes obgspüt wird (oda den Teil, wohin grod gsprungen wurde). Des erreichen mia, indem mia an Range Request erstöin.

1. Request

Dazu hängn mia an den Request folgenden Header o:

Range: bytes=STARTBYTE-ENDBYTE

sodass da Server woaß, wöchan Abschnitt er ausliefern soi. Des geht so allerdings nur, wenn mia direkt auf die Datei zugreifn. Also da Server den Download söba managt und die Datei valorbeit. Wenn des Ganze vorher no PHP durchlaufn soi, miassn mia uns dazu a eigenes Skript schreibn.

2. Server - Grundlagen / Range obfrogn

Dazu miassn mia im ersten Schritt rausfinden, wöcher Bereich zruckgebn wern soi. Dazu gibt's mehrere Möglichkeiten, de einfachste is aber, den Range via Regex rauszufiltern.

if (isset($_SERVER['HTTP_RANGE'])) {
  $range = preg_match('/^bytes=((\d*-\d*,? ?)+)$/', $_SERVER['HTTP_RANGE'], $matches) ? $matches[1] : [0, filesize("video.mp4")];
}

$range[0] enthoit jetzt den ersten Byte, den mia zruckgebn miassn. $range[1] enthoit den letztn Byte, den mia zruckgebn miassn. Wenn da Range-Header im Request ned gsetzt wurde, gebn mia die ganze Datei zruck - beginnen also bei Byte 0 und enden bei da Dateigröße in Bytes, de mia mit filesize() rausfinden kinnan. Jetzt miassn mia die Datei no auslesn, und zwoar zwischn dem Startbyte und dem Endbyte.

$fp = fopen('video.mp4', 'r');
fseek($fp, $range[0]);
echo fgets($fp, $range[1] - $range[0]);

Do öffnen mia die Datei in die Variable "fp". fseek setzt dabei den Cursor an die erste Byteposition, de mia zruckgebn solln, und fgets gibt die Anzoi an Bytes zruck, de mia auslesn miassn. Wichtig is also, dass mia ois zwoatn Parameter für die Funktion fgets ned des Endbyte söba übergebn, sondern die Anzoi an Bytes, de glesn wern soi (= Endbyte minus Startbyte). Jetzt kinnan mia also an Request mit am Header im Format

Range: bytes=Startbyte-Endbyte

senden.

3. Server - Erweitert

De Spezifikation unter tools.ietf.org beschreibt aber no weitere Möglichkeiten, an bestimmten Range anzufordern. Der entsprechende Teil schaut so aus:

The first 500 bytes:
Range: bytes=0-499

The second 500 bytes:
Range: bytes=500-999

All bytes except for the first 500 until the end of document:
Range: bytes=500-

The last 500 bytes of the document:
Range: bytes=-500

Two separate ranges:
Range: bytes=50-99,200-249

The first 100 bytes, 1000 bytes starting from the byte number 500,
and the remainder of the document starting from byte number 4000:
Range: bytes=0-99,500-1499,4000-

The first 100 bytes, 1000 bytes starting from the byte number 500,
and the last 200 bytes of the document:
Range: bytes=0-99,500-1499,-200

Mia miassn also außerdem no folgende Formate unterstützn, um RFC-konform zu bleiben:

  • Range: bytes=500- Olle Bytes ab Byte 500 bis zum End von da Datei
  • Range: bytes=-500 Die letztn 500 Bytes von da Datei
  • Range: bytes=50-99,200-249 Die Bytes 50-99 und 200-249

Und des Ganze a no kombiniert, wia z. B.

  • Range: bytes=0-99,500-1499,4000- Bytes 0-99, 500-1499, 4000 bis zum End von da Datei
  • Range: bytes=0-99,500-1499,-200 Bytes 0-99, 500-1499 und die letztn 200 Bytes von da Datei

Am einfachsten geht des Ganze über a foreach-Schleifn.

$fp = fopen('video.mp4', 'r');
$filesize = filesize("video.mp4");
foreach (split(substr($_SERVER['HTTP_RANGE'], 0, 6), ',') as $range) {
  preg_match_all("/(\d*)-(\d*)/", $range, $parts);
  if ($parts[2][0] == "") $parts[2][0] = $filesize;
  if ($parts[1][0] == "") {
    $parts[1][0] = $filesize - $parts[2][0];
    $parts[2][0] = $filesize;
  }
  fseek($fp, $parts[1][0]);
  echo fgets($fp, $parts[2][0] - $parts[1][0]);
}

Mia fangan dann an, die Datei ab Byte $parts[1][0] auszulesn, für a Länge vo $parts[2][0] - $parts[1][0] Bytes.

4. Hinweise

Zum Beachten is weiterhin, dass mia gegebenenfalls no an Fileheader aka MIME-Type in da PHP-Datei setzn miassn, damit da Browser woaß, um wöches Format es si handelt. Bei ana .mp4-Datei schaut des Ganze dann z. B. so aus:

header("Content-Type: video/mp4");
header("Content-Length: " . filesize("video.mp4"));

Olle MIME-Types findn mia auf da Seitn vo selfHTML.

NeicherSPAM-Protection-Methoden Nr. 3: Timing is wiedamoi ollesElterSPAM-Protection-Methoden Nr. 1: Honeypot