'audio/mpeg' ); function __construct() { parent::__construct(SZ_WEBAPI_API_DESCRIPTION_PATH); } protected function Process() { if (!strcasecmp($this->method, "list")) { $this->SlideshowMusicList(); } elseif (!strcasecmp($this->method, "get")) { session_write_close(); $this->GetMusic(); } else if (!strcasecmp($this->method, "add")) { $this->AddItem(); } else if (!strcasecmp($this->method, "edit")) { $this->Edit(); } else if (!strcasecmp($this->method, "delete")) { $this->Delete(); } } private function SlideshowMusicList() { $resp = array(); $params = $this->GetParams_List(); $data = SlideshowMusic::ListItem($params['offset'], $params['limit']); $items = array(); foreach ($data['data'] as $k => $v) { $v['id'] = $this->EncodeItemId($k); $items[] = $v; } $resp['items'] = $items; $resp['total'] = $data['total']; $offset = (0 > (int)$params['limit']) ? $resp['total'] : $params['offset'] + $params['limit']; $resp['offset'] = ($offset > $resp['total']) ? $resp['total'] : $offset; $this->SetResponse($resp); } private function GetMusic() { $id = $this->DecodeItemId($_REQUEST['id']); if (false === $id) { $this->SetError(WEBAPI_ERR_BAD_REQUEST); goto End; } $path = SlideshowMusic::GetMusicPath($id); if (!$path) { $this->SetError(PHOTOSTATION_SLIDESHOWMUSIC_NO_FILE); goto End; } @header("Content-Type: audio/mpeg"); @header("Content-Transfer-Encoding: binary"); $this->GetRangeDownload($path); exit; End: return; } private function GetRangeDownload($file) { $fp = @fopen($file, 'rb'); if (false == $fp) { return false; } $size = filesize($file); // File size $length = $size; // Content length $start = 0; // Start byte $end = $size - 1; // End byte // Now that we've gotten so far without errors we send the accept range header // At the moment we only support single ranges. // Multiple ranges requires some more work to ensure it works correctly // and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 // // Multirange support annouces itself with: // header('Accept-Ranges: bytes'); // // Multirange content must be sent with multipart/byteranges mediatype, // (mediatype = mimetype) // as well as a boundry header to indicate the various chunks of data. // //header("Accept-Ranges: 0-$length"); header('Accept-Ranges: bytes'); // multipart/byteranges // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 if (isset($_SERVER['HTTP_RANGE'])) { $c_start = $start; $c_end = $end; // Extract the range string list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); // Make sure the client hasn't sent us a multibyte range if (strpos($range, ',') !== false) { // (?) Shoud this be issued here, or should the first // range be used? Or should the header be ignored and // we output the whole content? header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes $start-$end/$size"); // (?) Echo some info to the client? exit; } // If the range starts with an '-' we start from the beginning // If not, we forward the file pointer // And make sure to get the end byte if spesified if ($range{0} == '-') { // The n-number of the last bytes is requested $c_start = $size - substr($range, 1); } else { $range = explode('-', $range); $c_start = $range[0]; $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; } // Check the range and make sure it's treated according to the specs. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html // // End bytes can not be larger than $end. $c_end = ($c_end > $end) ? $end : $c_end; // Validate the requested range and return an error if it's not correct. if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes $start-$end/$size"); // (?) Echo some info to the client? exit; } $start = $c_start; $end = $c_end; $length = $end - $start + 1; // Calculate new content length header('HTTP/1.1 206 Partial Content'); } // Notify the client the byte range we'll be outputting header("Content-Range: bytes $start-$end/$size"); header("Content-Length: $length"); // Start buffered download $this->OutputFileWithRange($fp, $start, $end); fclose($fp); } // this function output contain $end private function OutputFileWithRange($fp, $start, $end) { fseek($fp, $start); $buffer = 1024 * 8; while (!feof($fp) && ($end == -1 || ($p = ftell($fp)) <= $end)) { if ($p + $buffer > $end && $end != -1) { // In case we're only outputtin a chunk, make sure we don't // read past the length $buffer = $end - $p + 1; } echo fread($fp, $buffer); flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. } } private function AddItem() { $filename = $_FILES['file']['name']; $title = $_REQUEST['title']; if (!csSYNOPhotoMisc::IsMusicFile($filename)) { $this->SetError(PHOTOSTATION_SLIDESHOWMUSIC_FILE_EXT_ERR); goto End; } if (!isset($_FILES['file'])) { $this->SetError(PHOTOSTATION_SLIDESHOWMUSIC_NO_FILE); goto End; } if ($_FILES['file']['error'] > 0) { // files is not uploaded successfully by form upload $this->SetError(PHOTOSTATION_SLIDESHOWMUSIC_UPLOAD_ERROR); goto End; } if (SlideshowMusic::LIMIT <= SlideshowMusic::GetCount()) { $this->SetError(array(PHOTOSTATION_SLIDESHOWMUSIC_EXCEED_LIMIT, SlideshowMusic::LIMIT)); goto End; } if (!SlideshowMusic::Add($filename, $_FILES['file']['tmp_name'], $title)) { $this->SetError(PHOTOSTATION_SLIDESHOWMUSIC_SET_FAIL); goto End; } $resp = SlideshowMusic::GetLastInsertMusic(); $resp['id'] = $this->EncodeItemId($resp['id']); $this->SetResponse($resp); End: return; } private function Edit() { $params = $this->GetParams_Edit(); if (!$params) { $this->SetError(WEBAPI_ERR_BAD_REQUEST); goto End; } $res = SlideshowMusic::EditById($params['id'], $params['title'], $params['default']); if (!$res) { $this->SetError(PHOTOSTATION_SLIDESHOWMUSIC_SET_FAIL); } End: return; } private function Delete() { $params = $this->GetParams_Delete(); if (!$params) { $this->SetError(WEBAPI_ERR_BAD_REQUEST); goto End; } $res = SlideshowMusic::DeleteById($params['id']); if (!$res) { $this->SetError(PHOTOSTATION_SLIDESHOWMUSIC_SET_FAIL); } End: return; } private function GetParams_List() { // $variable + 0 => convert to integer $params = array( 'offset' => !isset($_REQUEST['offset']) || $_REQUEST['offset'] < 0 ? 0 : $_REQUEST['offset'] + 0, 'limit' => !isset($_REQUEST['limit']) || $_REQUEST['limit'] < 0 ? NULL : $_REQUEST['limit'] + 0, ); return $params; } private function GetParams_Edit() { if (!isset($_REQUEST['id']) || !((isset($_REQUEST['title']) && '' !== $_REQUEST['title']) || isset($_REQUEST['default']))) { return false; } $id = $this->DecodeItemId($_REQUEST['id']); if (false === $id) { return false; } $params = array( 'id' => $id, 'title' => $_REQUEST['title'], 'default' => isset($_REQUEST['default']) ? ("true" === $_REQUEST['default'] ? true : false) : NULL ); return $params; } private function GetParams_Delete() { if (!isset($_REQUEST['id'])){ return false; } $ids = explode(',', $_REQUEST['id']); $validIds= array(); foreach($ids as $id) { $decodeId = $this->DecodeItemId($id); if(false === $decodeId) { continue; } $validIds[] = $decodeId; } if (!count($validIds)) { return false; } $params = array( 'id' => $validIds ); return $params; } protected function CheckPermission() { $res = true; $check = array( "add" => $this->operationPemission, "edit" => $this->operationPemission, "delete" => $this->operationPemission ); if (!array_key_exists($this->method, $check)) { goto End; } $funcName = "check_".$check[$this->method]; if (!method_exists($this, $funcName)) { $res = false; goto End; } $res = $this->$funcName(); End: if (!$res) { $this->SetError(PHOTOSTATION_SLIDESHOWMUSIC_ACCESS_DENY); } return $res; } private function check_admin() { csSYNOPhotoDB::GetDBInstance()->SetSessionCache(); csSYNOPhotoMisc::CheckSessionTimeOut(true); return isset($_SESSION[SYNOPHOTO_ADMIN_USER]['admin_syno_user']); } } $api = new SlideshowMusicAPI(); $api->Run(); ?>