質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

アクセストークンが取得出来ない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 208

study_111

score 75

前提・実現したいこと

YoutubeDataApiV3のサンプルコードを元に、動画アップロード処理を記述したのですが、アクセストークンを取得する部分で、NULLとなってしまい、先の処理が行えない状況です。

発生している問題・エラーメッセージ

NULLとなってしまっているのは、以下の部分です。

var_dump($client->getAccessToken());

該当のソースコード

以下は、PHPコードの全文になります。

<?php
require_once __DIR__ . '/vendor/autoload.php';
session_start();

if ($_SERVER['REQUEST_METHOD'] == 'GET') {
    echo('getリクエストです');
    exit();
}

$err_msg = array();
$title = '';
$description = '';
$tag = '';
$tag_array = array();
$category_id = '';

// $tag_array[0] = 'aaa';
// var_dump($tag_array);
//拡張子取得
function getExt($filename)
{
    return pathinfo($filename, PATHINFO_EXTENSION);
}
// echo(__DIR__ );



//タイトル取得
if(isset($_POST['title'])){
    $title = $_POST['title'];
    // print($comment);
}

//説明
if(isset($_POST['description'])){
    $description = $_POST['description'];
    // print($comment);
}


//タグ
if(isset($_POST['tag'])){
    // echo('sss');
    $tag = $_POST['tag'];
    // echo($tag);
    if (mb_strlen($tag, 'UTF-8') > 500){
        $err_msg[] = 'タグに登録出来る文字数は500文字以内です';
    }else{
        $tag_array = explode(',',$tag);
        // $tag_array = array_filter($tag_array,'strlen');
        $tag_array = array_filter($tag_array,function($x){
            return preg_match("/\S+/misu",$x);
          });

        // var_dump($tag_array[3]);
        $tag_array = array_unique($tag_array);
        // var_dump($tag_array);
    }
}

if(isset($_POST['category'])){
    $category_id = $_POST['category'];
    // var_dump($category_id);
} 


if(isset($_FILES['certification_file']['tmp_name'])){
    // echo('jsonファイルは存在します');
    // echo($_FILES['certification_file']['tmp_name']);
    $ext = getExt($_FILES['certification_file']['name']);
    // echo(__LINE__);
    // echo($ext);

    if ($ext == "json"){
        // echo("jsonファイルです。");
        $certification_tmpfile = $_FILES['certification_file']['tmp_name'];
        $certification_filename = "./credentials/" . date("YmdHis");
        $certification_filename .= mt_rand();
        // $certification_filename = "./credentials/". $_FILES['certification_file']['name'];
        $certification_filename .= '.' . $ext;
        if (is_uploaded_file($certification_tmpfile)) {

            if ( move_uploaded_file($certification_tmpfile , $certification_filename)) {
            echo $certification_filename . "をアップロードしました。";
            } else {
                echo "ファイルをアップロードできません。";
            }

        } else {
            echo "ファイルが選択されていません。";
        }
    }else{
        echo("credentials.jsonファイルではありません。");
    }

    // echo($_FILES['certification_file']['type']);
    // echo($certification_filename);
    // echo "\n";

    // echo($certification_tmpfile);
}

if(isset($_FILES['movie_file']['tmp_name'])){

    $ext = getExt($_FILES['movie_file']['name']);

    $movie_tmpfile = $_FILES['movie_file']['tmp_name'];

    $movie_filename = "./movies/" . date("YmdHis");
    $movie_filename .= "." . $ext;

    if (is_uploaded_file($movie_tmpfile)) {

        if ( move_uploaded_file($movie_tmpfile , $movie_filename)) {
            echo $movie_filename . "をアップロードしました。";
        } else {
            echo "ファイルをアップロードできません。";
        }
    } else {
        echo "ファイルが選択されていません。";
    }

    // echo($movie_tmpfile);
}

// echo($movie_filename)."\n";



$url = $certification_filename;
$json = file_get_contents($url);
$json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
// echo($json);
$cert_arr = json_decode($json,true);
// var_dump($cert_arr);


if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
    throw new \Exception('please run "composer require google/apiclient:~2.0" in "' . __DIR__ .'"');
}

$OAUTH2_CLIENT_ID = $cert_arr['web']['client_id'];
$OAUTH2_CLIENT_SECRET = $cert_arr['web']['client_secret'];
echo($OAUTH2_CLIENT_ID);
echo '<br>';
echo($OAUTH2_CLIENT_SECRET);
// echo($_SERVER['HTTP_HOST'] );
$client = new Google_Client();
// var_dump($OAUTH2_CLIENT_ID);
// var_dump($OAUTH2_CLIENT_SECRET);
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'],
    FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);

// 使用するサービスを作成
$youtube = new Google_Service_YouTube($client);

// var_dump($youtube);
$tokenSessionKey = 'token-' . $client->prepareScopes();
if (isset($_GET['code'])) {
    if (strval($_SESSION['state']) !== strval($_GET['state'])) {
        die('The session state did not match.');
    }
    $client->authenticate($_GET['code']);
    $_SESSION[$tokenSessionKey] = $client->getAccessToken();
    header('Location: ' . $redirect);
}
if (isset($_SESSION[$tokenSessionKey])) {
    // echo(__LINE__);
    $client->setAccessToken($_SESSION[$tokenSessionKey]);
}

var_dump($client->getAccessToken());
// echo(__LINE__);
// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
    $htmlBody = '';
    echo(__LINE__);
    try{

      //アップロードするファイルパスへ置き換える
      $videoPath = $movie_filename;

      // Create a snippet with title, description, tags and category ID
      // Create an asset resource and set its snippet metadata and type.
      // This example sets the video's title, description, keyword tags, and
      // video category.

      $snippet = new Google_Service_YouTube_VideoSnippet();
      $snippet->setTitle($title);
      $snippet->setDescription($description);
      $snippet->setTags($tag_array);

      // Numeric video category. See
      // https://developers.google.com/youtube/v3/docs/videoCategories/list
      $snippet->setCategoryId($category_id);

      // Set the video's status to "public". Valid statuses are "public",
      // "private" and "unlisted".
      $status = new Google_Service_YouTube_VideoStatus();

      //公開ステータスは「非公開」に設定
      $status->privacyStatus = "private";

      // Associate the snippet and status objects with a new video resource.
      $video = new Google_Service_YouTube_Video();
      $video->setSnippet($snippet);
      $video->setStatus($status);

      // Specify the size of each chunk of data, in bytes. Set a higher value for
      // reliable connection as fewer chunks lead to faster uploads. Set a lower
      // value for better recovery on less reliable connections.
      $chunkSizeBytes = 1 * 1024 * 1024;

      // Setting the defer flag to true tells the client to return a request which can be called
      // with ->execute(); instead of making the API call immediately.
      $client->setDefer(true);

      // Create a request for the API's videos.insert method to create and upload the video.
      $insertRequest = $youtube->videos->insert("status,snippet", $video);
      var_dump($insertRequest);
      // Create a MediaFileUpload object for resumable uploads.
      $media = new Google_Http_MediaFileUpload(
          $client,
          $insertRequest,
          'video/*',
          null,
          true,
          $chunkSizeBytes
      );
      $media->setFileSize(filesize($videoPath));


      // Read the media file and upload it chunk by chunk.
      $status = false;
      $handle = fopen($videoPath, "rb");
      while (!$status && !feof($handle)) {
        $chunk = fread($handle, $chunkSizeBytes);
        $status = $media->nextChunk($chunk);
      }

      fclose($handle);

      // If you want to make other calls after the file upload, set setDefer back to false
      $client->setDefer(false);
//   echo('ssssss');

      $htmlBody .= "<h3>Video Uploaded</h3><ul>";
      $htmlBody .= sprintf('<li>%s (%s)</li>',
          $status['snippet']['title'],
          $status['id']);

      $htmlBody .= '</ul>';

    } catch (Google_Service_Exception $e) {
      $htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
          htmlspecialchars($e->getMessage()));
    } catch (Google_Exception $e) {
      $htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
          htmlspecialchars($e->getMessage()));
    }

    $_SESSION[$tokenSessionKey] = $client->getAccessToken();
  } elseif ($OAUTH2_CLIENT_ID == 'REPLACE_ME') {
    $htmlBody = <<<END
    <h3>Client Credentials Required</h3>
    <p>
      You need to set <code>\$OAUTH2_CLIENT_ID</code> and
      <code>\$OAUTH2_CLIENT_ID</code> before proceeding.
    <p>
END;
  } else {
    // If the user hasn't authorized the app, initiate the OAuth flow
    $state = mt_rand();
    $client->setState($state);
    $_SESSION['state'] = $state;

    $authUrl = $client->createAuthUrl();
    $htmlBody = <<<END
    <h3>Authorization Required</h3>
    <p>You need to <a href="$authUrl">authorize access</a> before proceeding.<p>
END;
  }
  ?>
<!-- // // // $url = __DIR__ . ; -->

補足情報(FW/ツールのバージョンなど)

「OAUTH2_CLIENT_ID」と「OAUTH2_CLIENT_SECRET」には、値が入っていることが、以下の部分で確認できている状況です。

echo($OAUTH2_CLIENT_ID);
echo '<br>';
echo($OAUTH2_CLIENT_SECRET);
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • asahina1979

    2020/07/10 20:43

    そもそもアクセストークン取得するための認可が動作してませんよね。
    OAUTH の動きをしっていたら

    1枚でやるなら GET 禁止 の時点で認可が正常終了していません

    キャンセル

  • study_111

    2020/07/10 21:19

    サンプルコードをそのまま使用する形としたのですが、どこら辺の部分の修正、追記が必要になってくるのでしょうか?

    キャンセル

回答 1

checkベストアンサー

+1

エラーが出る時は試しにローカルで実行してみようとした時と推測します。

残念ながら、サンプルコードそのままではローカルで実行できません。詳しいドキュメントは OAuth 2.0 Flow: Server-side web apps にでありますが、そこの情報量が多すぎて、まとめてみます。

OAuth という認証プロセスは、下記の流れで実行されます:

  1. PHPは認証リクエストをGoogleに送ります
  2. Googleはユーザーにログインを求めます
  3. Googleはユーザーがログインしてから、PHPの必要権限を求めます
  4. Googleはユーザーの同意を受けてから、ユーザーをPHPへリダイレクトします
  5. PHPはリダイレクトに含めたデータを処理し、アクセストークンを取得します

ローカルで作動できない部分はその4です。リダイレクトの必要があるので、パブリックサーバーを立ち上げ、そのサーバーでの下記の $redirect 変数の値で Google アプリコンソールに設定しないといけません。

$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'],
    FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);

色々大変そうな設定ですが、頑張ってください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/21 19:12

    ご回答ありがとうございます。
    自分は、実行の方はローカル環境で行いました。
    googleにログインしたブラウザで、formの値を入力しphp側への送信を行う形としました。
    教えて下さりました「Googleはユーザーの同意を受けてから、ユーザーをPHPへリダイレクトします」こちらの部分なのですが、google側のサーバーからローカル側への通信が出来ない為に起こることなのでしょうか?
    自分が思い違いをしてしまっていたら申し訳ないのですが、ローカル環境であっても外部との通信は可能ではないかと思うのですが、そういった意味ではありませんでしょうか?
    勉強不足で申し訳ないのですが、何卒ご助言頂けましたら幸いです。

    キャンセル

  • 2020/07/21 19:47

    ご理解はぴったりです。ただ、インターネットは複雑です。ローカル環境で外部との通信は、ローカルから外へのリクエストと外からローカルへのレスポンスに限られています。外からローカルへリクエストをできません。ローカルであるため、外からローカル環境がどこかすらわかりませんので。リダイレクトはリクエストの一種ですので、ローカルへできません。

    キャンセル

  • 2020/07/21 20:13 編集

    ご返信ありがとうございます。
    大変分かりやすいご説明で助かります。一度、パブリックなサーバーを立てて実行してみたいと思います。
    いつもいつもご親切に教えて下さり、誠に感謝です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る