Google API php client: отправить etag

Я использую последнюю библиотеку клиентов Google PHP . Как я могу отправить etag с этой библиотекой?

Я уже пробовал что-то вроде этого:

$opt_params = array( 'etag' => 'F9iA7pnxqNgrkOutjQAa9F2k8HY/mOihMVEDLCvdSVCzwDmYHpSV'); $response = $youtube->channels->listChannels('snippet', array('id' => $channel_id), $opt_params); 

Благодаря!

Этот пост немного длинный (если не слишком длинный). Если вам просто нужен прокрутка кода и пропустите мои обсуждения. Пожалуйста, продолжайте, как хотите.

Задний план

Я не знаю, понял ли кто-нибудь решение для этого. Ответ Coded Monkey – это начало. Проблема заключается в том, что представленное им решение предполагает, что API делает запрос, используя только ключ разработчика / api, а не ключ доступа oauth . Если вы попробуете свой код с помощью ключа разработчика, вы получите следующее:

Ошибка при вызове GET https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet%2Cstatus&mine=true&maxResults=50&key= {ключ разработчика здесь} : (401) Требуется вход

Ключ разработчика недостаточно для получения данных пользователя youtube, а ключ разработчика не предоставляет доступ к любой информации учетной записи . Это включает данные youtube. Для доступа к данным youtube необходимо использовать ключ доступа oauth (читайте здесь: api keys )

Обратите внимание, что ключ разработчика становится частью строки запроса. С другой стороны, когда вы используете ключ oauth, ключ становится заголовком запроса:

Авторизация: Bearer {oauth key здесь}

Однако, если вы попытаетесь использовать ключ oauth, вы все равно получите ту же ошибку, что и выше. Это довольно неприятно . И я думаю, именно поэтому ответ Кодированной Обезьяны не получился. Чтобы понять, почему, нужно понимать, как клиент Google отправляет запросы.

Как работает клиент Google PHP

Мое объяснение того, как клиент Google работает за сценой, не является полным и основывается только на том, что я узнал из своего опыта в определении того, как решить эту проблему.

Клиент google, который я буду называть $client , использует Google_IO_Abstract класса Google_IO_Abstract , я буду называть $io для отправки запросов. Можно получить текущий экземпляр $io и изменить его с помощью методов $client->setIo() и $client->getIo() . Google_IO_Abstract – абстрактный класс. Одним из его конкретных подклассов, доступных в PHP API API, является Google_IO_Curl . Как видно из названия, класс использует curl .

С этого момента я буду считать, что $io является экземпляром Google_IO_Curl . Следующий (из решения Code Mokey):

 $client->getIo()->setOptions(array( CURLOPT_HTTPHEADER => array('If-None-Match: "4FSIjSQU83ZJMYAO0IqRYMvZX98/OPaxOhv3eeKc9owSnDQugGfL8ss"'), )); 

добавит HTTP-заголовок If-None-Match в параметр заголовка curl. Фактическое добавление заголовка происходит только тогда, когда $io->executeRequest($request) . $request – запрос, который необходимо отправить $client .

Настройка заголовка curl выполняется через curl_setopt($curl, CURLOPT_HTTPHEADER, $headers) , где $curl – это curl-экземпляр, а $headers – массив заголовков.

Если вы прочитаете реализацию executeRequest . Вы увидите, что большинство деталей предназначены для установки параметров завитка. Одна важная часть – сбор заголовков http из $request в массив с именем $curlHeaders как показано ниже (это из исходного кода Google_IO_Curl ). Здесь также добавлен заголовок Authorization .

  $requestHeaders = $request->getRequestHeaders(); if ($requestHeaders && is_array($requestHeaders)) { $curlHeaders = array(); foreach ($requestHeaders as $k => $v) { $curlHeaders[] = "$k: $v"; } curl_setopt($curl, CURLOPT_HTTPHEADER, $curlHeaders); } 

Обратите внимание, что после сбора заголовков curl_setopt() вызывается для установки параметров заголовка curl. Теперь возникает проблема, после того, как эти строки кода входят в ту часть, где установлены дополнительные параметры. Параметры, заданные с помощью setOptions() , что означает, что будет еще один вызов curl_setopt($curl, CURLOPT_HTTPHEADER, $headers) но на этот раз $ headers будет содержать заголовок If-None-Match. Этот второй вызов заменит все предыдущие заголовки . Вуаля! Заголовок Authorization отсутствует. Я не уверен, что кто-то сообщил об этом еще. Я не уверен, что это намеренно. Но это действительно неприятно для начинающих, таких как я .

Во всяком случае, я придумал быстрое решение.

Мое решение

Я остановлю свое обсуждение здесь и вместо этого дам вам код ( Google_IO_Curl_Mod.php ):

 <?php /** * Wrapper class for Google_IO_Curl. * * This class fixes issues involving request headers added using setOptions() * * @author Russel Villacarlos<cvsurussel_AT_gmail.com> */ if (!class_exists('Google_Client')) { require_once 'Google/autoload.php'; } class Google_IO_Curl_Mod extends Google_IO_Curl { //Google_IO_Curl instance private $io; //Array for additional headers added using setOptions() private $headers; public function __construct(Google_IO_Curl $io) { $this->io = $io; $this->headers=[]; } /** * Execute an HTTP Request * * @param Google_Http_Request $request the http request to be executed * @return array containing response headers, body, and http code * @throws Google_IO_Exception on curl or IO error */ public function executeRequest(Google_Http_Request $request) { foreach ($this->headers as $value) { if(is_string($value) && strpos($value,":")!==false){ $header = split(":\s*",$value); $request->setRequestHeaders(array($header[0]=>$header[1])); } } $result = $this->io->executeRequest($request); return $result; } /** * Set options that update the transport implementation's behavior. * @param $options */ public function setOptions($options) { if($options){ if(array_key_exists(CURLOPT_HTTPHEADER, $options)){ $this->headers= array_merge($this->headers, $options[CURLOPT_HTTPHEADER]); unset($options[CURLOPT_HTTPHEADER]); } $this->io->setOptions($options); } } /** * Set the maximum request time in seconds. * @param $timeout in seconds */ public function setTimeout($timeout) { $this->io->setTimeout($timeout); } /** * Get the maximum request time in seconds. * @return timeout in seconds */ public function getTimeout() { return $this->io->getTimeout(); } /** * Test for the presence of a cURL header processing bug * * {@inheritDoc} * * @return boolean */ protected function needsQuirk() { return $this->io->needsQuirk(); } } не <?php /** * Wrapper class for Google_IO_Curl. * * This class fixes issues involving request headers added using setOptions() * * @author Russel Villacarlos<cvsurussel_AT_gmail.com> */ if (!class_exists('Google_Client')) { require_once 'Google/autoload.php'; } class Google_IO_Curl_Mod extends Google_IO_Curl { //Google_IO_Curl instance private $io; //Array for additional headers added using setOptions() private $headers; public function __construct(Google_IO_Curl $io) { $this->io = $io; $this->headers=[]; } /** * Execute an HTTP Request * * @param Google_Http_Request $request the http request to be executed * @return array containing response headers, body, and http code * @throws Google_IO_Exception on curl or IO error */ public function executeRequest(Google_Http_Request $request) { foreach ($this->headers as $value) { if(is_string($value) && strpos($value,":")!==false){ $header = split(":\s*",$value); $request->setRequestHeaders(array($header[0]=>$header[1])); } } $result = $this->io->executeRequest($request); return $result; } /** * Set options that update the transport implementation's behavior. * @param $options */ public function setOptions($options) { if($options){ if(array_key_exists(CURLOPT_HTTPHEADER, $options)){ $this->headers= array_merge($this->headers, $options[CURLOPT_HTTPHEADER]); unset($options[CURLOPT_HTTPHEADER]); } $this->io->setOptions($options); } } /** * Set the maximum request time in seconds. * @param $timeout in seconds */ public function setTimeout($timeout) { $this->io->setTimeout($timeout); } /** * Get the maximum request time in seconds. * @return timeout in seconds */ public function getTimeout() { return $this->io->getTimeout(); } /** * Test for the presence of a cURL header processing bug * * {@inheritDoc} * * @return boolean */ protected function needsQuirk() { return $this->io->needsQuirk(); } } 

Чтобы использовать это, выполните следующие действия:

 $client = new Google_Client(); //codes for setting the oauth credential appears here $io = new Google_IO_Curl_Mod(new Google_IO_Curl($client)); $client->setIo($io); $client->getIo()->setOptions(array( CURLOPT_HTTPHEADER => array('If-None-Match: "NO6QTeg0-3ShswIeqLchQ_mzWJs/wtg8du-olFPZ73k6UW7Jk5JcwpQ"'), )); //codes for calling youtube api or any google api goes here 

Обратите внимание, что пара двойных кавычек является частью etag.

Клиент PHP API Google не имеет встроенной поддержки etags . Тем не менее, вы все равно можете изменить запрос curl и применить etag в качестве заголовка.

К сожалению, Google_Http_REST выбрасывает исключение, когда он получает заголовок 304 Not Modified поэтому вам придется обрабатывать их отдельно в catch -block.

Это результирующий PHP-код (обратите внимание, что это для версии 1 клиента PHP API Google):

 class EmptyResponse { } $DEVELOPER_KEY = ''; $client = new Google_Client(); $client->setDeveloperKey($DEVELOPER_KEY); $youtube = new Google_Service_YouTube($client); // Do some logic, catch some resources // .. // Set the "If-None-Match" header for the etag // This assumes the Google API is using CURL $client->getIo()->setOptions(array( CURLOPT_HTTPHEADER => array('If-None-Match: "4FSIjSQU83ZJMYAO0IqRYMvZX98/OPaxOhv3eeKc9owSnDQugGfL8ss"'), )); try { $response = $youtube->playlists->listPlaylists('snippet', array( 'id' => 'PLOIvOnfHWjIkiz6fd5KYUXJY6ZpHRqPfW', )); } catch (Google_Service_Exception $e) { if (304 == $e->getCode()) { // If the error code is 304 (Not Modified) return an empty response $response = new EmptyResponse; } else { // The request was unsuccesful $response = null; } } // After the request set the headers back to default $client->getIo()->setOptions(array( CURLOPT_HTTPHEADER => array(), )); var_dump($response); // Catch some more resources // ... 

Если вы проверите документацию для channels.list, вы заметите, что etag не является одним из необязательных параметров.

Таким образом, вы не можете отправить etag для перечисления каналов через api, это не ограничение клиентской библиотеки.