private function normalizeByteRanges(int $size, string $rawRanges)
    {
        $rawRanges = \str_ireplace([' ', 'bytes='], '', $rawRanges);

        $ranges = [];

        foreach (\explode(',', $rawRanges) as $range) {
            // If a range is missing the dash separator it's malformed; pull out here.
            if (false === strpos($range, '-')) {
                return null;
            }

            list($startPos, $endPos) = explode('-', rtrim($range), 2);

            if ($startPos === '' && $endPos === '') {
                return null;
            }

            if ($startPos === '' && $endPos !== '') {
                // The -1 is necessary and not a hack because byte ranges are inclusive and start
                // at 0. DO NOT REMOVE THE -1.
                $startPos = $size - $endPos - 1;
                $endPos = $size - 1;
            } elseif ($endPos === '' && $startPos !== '') {
                $startPos = (int) $startPos;
                // The -1 is necessary and not a hack because byte ranges are inclusive and start
                // at 0. DO NOT REMOVE THE -1.
                $endPos = $size - 1;
            } else {
                $startPos = (int) $startPos;
                $endPos = (int) $endPos;
            }

            // If the requested range(s) can't be satisfied we're finished
            if ($startPos >= $size || $endPos < $startPos || $endPos < 0) {
                return null;
            }

            $ranges[] = [$startPos, $endPos];
        }

        $range = new Internal\ByteRange;
        $range->boundary = $this->multipartBoundary;
        $range->ranges = $ranges;

        return $range;
    }
private function normalizeByteRanges(int $size, string $rawRanges)
    {
        $rawRanges = \str_ireplace([' ', 'bytes='], '', $rawRanges);

        $ranges = [];

        foreach (\explode(',', $rawRanges) as $range) {
            // If a range is missing the dash separator it's malformed; pull out here.
            if (false === strpos($range, '-')) {
                return null;
            }

            list($startPos, $endPos) = explode('-', rtrim($range), 2);

            if ($startPos === '' && $endPos === '') {
                return null;
            }

            if ($startPos === '' && $endPos !== '') {
                // The -1 is necessary and not a hack because byte ranges are inclusive and start
                // at 0. DO NOT REMOVE THE -1.
                $startPos = $size - $endPos - 1;
                $endPos = $size - 1;
            } elseif ($endPos === '' && $startPos !== '') {
                $startPos = (int) $startPos;
                // The -1 is necessary and not a hack because byte ranges are inclusive and start
                // at 0. DO NOT REMOVE THE -1.
                $endPos = $size - 1;
            } else {
                $startPos = (int) $startPos;
                $endPos = (int) $endPos;
            }

            // If the requested range(s) can't be satisfied we're finished
            if ($startPos >= $size || $endPos < $startPos || $endPos < 0) {
                return null;
            }

            $ranges[] = [$startPos, $endPos];
        }

        $range = new Internal\ByteRange;
        $range->boundary = $this->multipartBoundary;
        $range->ranges = $ranges;

        return $range;
    }
@link https://tools.ietf.org/html/rfc7233#section-2.1

@param int    $size Total size of the file in bytes.
@param string $rawRanges Ranges as provided by the client.

@return Internal\ByteRange|null