Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
e64c30e569
|
|||
7a8dede10b
|
|||
ad8183b41f | |||
aaaba0e2f1 | |||
3e1288a68c | |||
4b2cbfb384 | |||
2a98464bbe | |||
c54e75a899 | |||
9b92776607 | |||
0ef2575001 | |||
5b8e15a1e0 | |||
c387953040 | |||
3184973867 | |||
2a16b836b7 | |||
38a962cbdc | |||
3ff00fde72 | |||
c98606734a | |||
a3fddb495d | |||
37bc9d5ec6 | |||
d474f40403 | |||
c0d64e81aa | |||
4de63bd94b | |||
d6977ef4dc | |||
48edb42c1e | |||
120617847c | |||
3699fd5ecb |
83
src/Mp3FileLocal.php
Normal file
83
src/Mp3FileLocal.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace wapmorgan\Mp3Info;
|
||||
|
||||
class Mp3FileLocal
|
||||
{
|
||||
public string $fileName;
|
||||
|
||||
protected int $fileSize;
|
||||
|
||||
private $_filePtr;
|
||||
|
||||
/**
|
||||
* Creates a new local file object.
|
||||
*
|
||||
* @param string $fileName URL to open
|
||||
*/
|
||||
public function __construct(string $fileName)
|
||||
{
|
||||
$this->fileName = $fileName;
|
||||
$this->_filePtr = fopen($this->fileName, 'rb');
|
||||
$this->fileSize = filesize($this->fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file size
|
||||
*
|
||||
* @return int File size
|
||||
*/
|
||||
public function getFileSize(): int
|
||||
{
|
||||
return $this->fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given amount of Bytes from the current file position.
|
||||
*
|
||||
* @param int $numBytes Bytes to read
|
||||
*
|
||||
* @return string Read Bytes
|
||||
*/
|
||||
public function getBytes(int $numBytes): string
|
||||
{
|
||||
return fread($this->_filePtr, $numBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current file position
|
||||
*
|
||||
* @return int File position
|
||||
*/
|
||||
public function getFilePos(): int
|
||||
{
|
||||
return ftell($this->_filePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file point to the given position.
|
||||
*
|
||||
* @param int $posBytes Position to jump to
|
||||
*
|
||||
* @return bool TRUE if successful
|
||||
*/
|
||||
public function seekTo(int $posBytes): bool
|
||||
{
|
||||
$result = fseek($this->_filePtr, $posBytes);
|
||||
return ($result == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the file pointer the given amount.
|
||||
*
|
||||
* @param int $posBytes Bytes to advance
|
||||
*
|
||||
* @return bool TRUE if successful
|
||||
*/
|
||||
public function seekForward(int $posBytes): bool
|
||||
{
|
||||
$newPos = $this->getFilePos() + $posBytes;
|
||||
return $this->seekTo($newPos);
|
||||
}
|
||||
|
||||
}
|
190
src/Mp3FileRemote.php
Normal file
190
src/Mp3FileRemote.php
Normal file
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace wapmorgan\Mp3Info;
|
||||
|
||||
use \Exception;
|
||||
|
||||
class Mp3FileRemote
|
||||
{
|
||||
public string $fileName;
|
||||
public int $blockSize;
|
||||
|
||||
protected $buffer;
|
||||
protected int $filePos;
|
||||
protected $fileSize;
|
||||
|
||||
/**
|
||||
* Creates a new remote file object.
|
||||
*
|
||||
* @param string $fileName URL to open
|
||||
* @param int $blockSize Size of the blocks to query from the server (default: 4096)
|
||||
*/
|
||||
public function __construct(string $fileName, int $blockSize = 4096)
|
||||
{
|
||||
$this->fileName = $fileName;
|
||||
$this->blockSize = $blockSize;
|
||||
$this->buffer = [];
|
||||
$this->filePos = 0;
|
||||
$this->fileSize = $this->_readFileSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file size
|
||||
*
|
||||
* @return int File size
|
||||
*/
|
||||
public function getFileSize(): int
|
||||
{
|
||||
return $this->fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a HEAD request to get the file size
|
||||
*
|
||||
* @return int Content-Length header
|
||||
*/
|
||||
private function _readFileSize(): int
|
||||
{
|
||||
// make HTTP HEAD request to get Content-Length
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'HEAD',
|
||||
],
|
||||
]);
|
||||
$result = get_headers($this->fileName, true, $context);
|
||||
$result = array_change_key_case($result, CASE_LOWER);
|
||||
return $result['content-length'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given amount of Bytes from the current file position.
|
||||
*
|
||||
* @param int $numBytes Bytes to read
|
||||
*
|
||||
* @return string Read Bytes
|
||||
*/
|
||||
public function getBytes(int $numBytes): string
|
||||
{
|
||||
$blockId = intdiv($this->filePos, $this->blockSize);
|
||||
$blockPos = $this->filePos % $this->blockSize;
|
||||
|
||||
$output = [];
|
||||
|
||||
do {
|
||||
// make sure we have this block
|
||||
if (!$this->downloadBlock($blockId)) {
|
||||
throw new Exception('Error downloading block ' . $blockId . ' (starting at pos. ' . ($blockId * $this->blockSize) . ')!');
|
||||
}
|
||||
if ($blockPos + $numBytes >= $this->blockSize) {
|
||||
// length of request is more than this block has, truncate to block len
|
||||
$subLen = $this->blockSize - $blockPos;
|
||||
} else {
|
||||
// requested length fits inside this block
|
||||
$subLen = $numBytes;
|
||||
}
|
||||
// $subLen = ($blockPos + $numBytes >= $this->blockSize) ? ($this->blockSize - $blockPos) : $numBytes;
|
||||
$output[] = substr($this->buffer[$blockId], $blockPos, $subLen);
|
||||
$this->filePos += $subLen;
|
||||
$numBytes -= $subLen;
|
||||
// advance to next block
|
||||
$blockPos = 0;
|
||||
$blockId++;
|
||||
} while ($numBytes > 0);
|
||||
|
||||
return implode('', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current file position
|
||||
*
|
||||
* @return int File position
|
||||
*/
|
||||
public function getFilePos(): int
|
||||
{
|
||||
return $this->filePos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file pointer to the given position.
|
||||
*
|
||||
* @param int $posBytes Position to jump to
|
||||
*
|
||||
* @return bool TRUE if successful
|
||||
*/
|
||||
public function seekTo(int $posBytes): bool
|
||||
{
|
||||
if ($posBytes < 0 || $posBytes > $this->fileSize) {
|
||||
return false;
|
||||
}
|
||||
$this->filePos = $posBytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the file pointer the given amount.
|
||||
*
|
||||
* @param int $posBytes Bytes to advance
|
||||
*
|
||||
* @return bool TRUE if successful
|
||||
*/
|
||||
public function seekForward(int $posBytes): bool
|
||||
{
|
||||
$newPos = $this->filePos + $posBytes;
|
||||
return $this->seekTo($newPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the given block if needed
|
||||
*
|
||||
* @param int $blockNo Block to download
|
||||
*
|
||||
* @return bool TRUE if successful
|
||||
*/
|
||||
protected function downloadBlock(int $blockNo): bool
|
||||
{
|
||||
if (array_key_exists($blockNo, $this->buffer)) {
|
||||
// already downloaded
|
||||
return true;
|
||||
}
|
||||
$bytesFrom = $blockNo * $this->blockSize;
|
||||
$bytesTo = $bytesFrom + $this->blockSize - 1;
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'GET',
|
||||
'header' => [
|
||||
'Range: bytes=' . $bytesFrom . '-' . $bytesTo,
|
||||
],
|
||||
],
|
||||
]);
|
||||
$filePtr = fopen($this->fileName, 'rb', false, $context);
|
||||
if ($filePtr === false) {
|
||||
return false;
|
||||
}
|
||||
$this->buffer[$blockNo] = fread($filePtr, $this->blockSize);
|
||||
$status = stream_get_meta_data($filePtr);
|
||||
$httpStatus = explode(' ', $status['wrapper_data'][0])[1];
|
||||
if ($httpStatus != '206') {
|
||||
if ($httpStatus != '200') {
|
||||
echo 'Download error!' . PHP_EOL;
|
||||
var_dump($status);
|
||||
return false;
|
||||
}
|
||||
echo 'Server doesn\'t support partial content!' . PHP_EOL;
|
||||
// Content received is whole file from start
|
||||
if ($blockNo != 0) {
|
||||
// move block to start if needed
|
||||
$this->buffer[0] =& $this->buffer[$blockNo];
|
||||
unset($this->buffer[$blockNo]);
|
||||
$blockNo = 0;
|
||||
}
|
||||
// receive remaining parts while we're at it
|
||||
while (!feof($filePtr)) {
|
||||
$blockNo++;
|
||||
$this->buffer[$blockNo] = fread($filePtr, $this->blockSize);
|
||||
}
|
||||
}
|
||||
fclose($filePtr);
|
||||
return true;
|
||||
}
|
||||
}
|
734
src/Mp3Info.php
734
src/Mp3Info.php
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user