Я, вероятно, не должен был отвечать на этот вопрос, но у меня было немного свободного времени на работе и я хотел немного поиграть с сокетами.
Вот мой класс, он не очень хорошо протестирован (ну, он работал при первом запуске, что подозрительно) и может содержать ошибки, но он может дать вам несколько полезных идей.Он удаляет заголовки ICY * в качестве примера, который вы опубликовали, но это можно легко изменить.
Я проверил его на плеере Ubuntu Totem, и он хорошо играл в течение 10 минут, прежде чем я остановил его, но, возможно, мне просто повезло (: По крайней мере, 8 минут, похоже, не магическое число.
<?php
ob_start();
class RadioProxy {
CONST STREAM_content_type='audio/aac';
CONST STREAM_timeout=1.5;
CONST HTTP_response_header_first='/\s200\s/';
CONST HTTP_response_header_pattern='/^[a-z\-]+:/i';
CONST HTTP_max_line_length=1024;
CONST HTTP_delim="\r\n";
CONST HTTP_max_response_headers=40;
CONST ERROR_max=5;
CONST ERROR_interval=120;
CONST ERROR_usleep=300000;
private $server_name, $server_port;
private $HTTP_headers;
private $STREAM = NULL;
private $STREAM_errors = array();
private $TIMEOUT_seconds, $TIMEOUT_microseconds;
public function __construct($server_name, $server_port, $filename='') {
self::STREAM_set_headers();
$this->server_name = $server_name;
$this->server_port = $server_port;
$this->HTTP_headers = $this->HTTP_generate_headers($filename);
$this->connect();
}
private function connect() {
$HTTP_headers_length = strlen($this->HTTP_headers);
do {
if (!$this->STREAM_connect()) {
continue;
}
if (!$this->STREAM_send_headers()) {
continue;
}
if (!$this->STREAM_skip_headers()) {
continue;
}
if (!$this->STREAM_proxy()) {
continue;
}
} while ($this->ERROR_is_accepteble());
}
private function HTTP_generate_headers($filename) {
$header = '';
self::HTTP_add_header($header, 'GET /' . rawurlencode($filename) . ' HTTP/1.0');
self::HTTP_add_header($header, 'Host: ' . $this->server_name);
self::HTTP_add_header($header, 'User-Agent: WinampMPEG/5.11');
self::HTTP_add_header($header, 'Accept: */*');
self::HTTP_add_header($header, 'Connection: close');
//End of headers
self::HTTP_add_header($header);
return $header;
}
private static function HTTP_add_header(&$header, $new_header_line='') {
$header.=$new_header_line . self::HTTP_delim;
}
private function ERROR_is_accepteble() {
//Delete old errors
array_filter($this->STREAM_errors, 'self::ERROR_remove_old');
$this->STREAM_errors[] = time();
usleep(self::ERROR_usleep);
return count($this->STREAM_errors) <= self::ERROR_max;
}
private static function ERROR_remove_old($error_time) {
return ($error_time - time()) <= self::ERROR_interval;
}
private function STREAM_connect() {
if (!ob_get_level()) {
ob_start();
}
ob_clean();
if ($this->STREAM !== NULL) {
fclose($this->STREAM);
}
$this->STREAM = fsockopen($this->server_name, $this->server_port);
if ($this->STREAM === FALSE) {
return FALSE;
}
$this->TIMEOUT_seconds = floor(self::STREAM_timeout);
$this->TIMEOUT_microseconds = ceil((self::STREAM_timeout - $this->TIMEOUT_seconds) * 1000);
return stream_set_timeout($this->STREAM, $this->TIMEOUT_seconds, $this->TIMEOUT_microseconds);
}
private function STREAM_send_headers() {
return fwrite($this->STREAM, $this->HTTP_headers) === strlen($this->HTTP_headers);
}
private function STREAM_skip_headers() {
$read_expect = array($this->STREAM);
$if_first_header = true;
$header_lines_count = 0;
do {
stream_select($read_expect, $NULL, $NULL, $this->TIMEOUT_seconds, $this->TIMEOUT_microseconds);
$header_line = stream_get_line($this->STREAM, self::HTTP_max_line_length, self::HTTP_delim);
if ($header_line === FALSE) {
return FALSE;
}
if ($if_first_header) {
$if_first_header = false;
if (!preg_match(self::HTTP_response_header_first, $header_line)) {
return FALSE;
}
continue;
}
if (empty($header_line)) {
return TRUE;
}
if (!preg_match(self::HTTP_response_header_pattern, $header_line)) {
return FALSE;
}
$header_lines_count++;
} while ($header_lines_count < self::HTTP_max_response_headers);
return FALSE;
}
private function STREAM_proxy() {
$read_expect = array($this->STREAM);
//No output buffering should be here!
while (@ob_end_clean ());
do {
stream_select($read_expect, $NULL, $NULL, $this->TIMEOUT_seconds, $this->TIMEOUT_microseconds);
} while (fpassthru($this->STREAM));
}
private static function STREAM_set_headers() {
//Clean all output
ob_clean();
header("Content-type: " . self::STREAM_content_type);
ob_flush();
}
}
$TestRadio = new RadioProxy('XXX.XXX.XXX.XXX', XXXX,'XXXX.mp3');
PS Не делайте этого.