asXml(); exit; } // Authenticate the user with preemptive HTTP Basic authentication first $user = $_SERVER['PHP_AUTH_USER']; if (empty($user)) { $user = $_GET['u']; } $password = $_SERVER['PHP_AUTH_PW']; if (empty($password)) { $password = $_GET['p']; } $version = $_GET['v']; $clientapp = $_GET['c']; if (empty($user) || empty($password) || empty($version) || empty($action) || empty($clientapp)) { ob_end_clean(); echo Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_MISSINGPARAM)->asXml(); exit(); } // Decode hex-encoded password $encpwd = strpos($password, "enc:"); if ($encpwd !== false) { $hex = substr($password, 4); $decpwd = ''; for ($i=0; $iasXml(); exit(); } if (!Access::check_network('init-api', $user, 5)) { debug_event('Access Denied','Unauthorized access attempt to Subsonic API [' . $_SERVER['REMOTE_ADDR'] . ']', '3'); ob_end_clean(); echo Subsonic_XML_Data::createError(SSERROR_UNAUTHORIZED, 'Unauthorized access attempt to Subsonic API - ACL Error'); exit(); } $GLOBALS['user'] = User::get_from_username($user); // Check server version if (version_compare(Subsonic_XML_Data::API_VERSION, $version) < 0) { ob_end_clean(); echo Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_APIVERSION_SERVER)->asXml(); exit(); } // Get the list of possible methods for the Ampache API $methods = get_class_methods('subsonic_api'); // Define list of internal functions that should be skipped $internal_functions = array('check_version', 'check_parameter', 'follow_stream', '_updatePlaylist'); // We do not use $_GET because of multiple parameters with the same name $query_string = $_SERVER['QUERY_STRING']; // Trick to avoid $HTTP_RAW_POST_DATA $postdata = file_get_contents("php://input"); if (!empty($postdata)) { $query_string .= '&' . $postdata; } $query = explode('&', $query_string); $params = array(); foreach ($query as $param) { list($name, $value) = explode('=', $param); $decname = urldecode($name); $decvalue = urldecode($value); if (array_key_exists($decname, $params)) { if (!is_array($params[$decname])) { $oldvalue = $params[$decname]; $params[$decname] = array(); $params[$decname][] = $oldvalue; } $params[$decname][] = $decvalue; } else { $params[$decname] = $decvalue; } } //syslog(LOG_INFO, print_r($params, true)); // Recurse through them and see if we're calling one of them foreach ($methods as $method) { if (in_array($method,$internal_functions)) { continue; } // If the method is the same as the action being called // Then let's call this function! if ($action == $method) { call_user_func(array('subsonic_api',$method),$params); // We only allow a single function to be called, and we assume it's cleaned up! exit(); } } // end foreach methods in API // If we manage to get here, we still need to hand out an XML document ob_end_clean(); echo Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND)->asXml(); ?>