4

I am using the php code sample for uploading a video provided by youtube, which can be found here: https://developers.google.com/youtube/v3/code_samples/php#upload_a_video

However, when the session starts, it requires the user to authorise it, so it takes you to the authorise page, then redirects you back. On doing this, it uploads twice, I assume it is trying to upload the video it could not do when it was not authorised. It only double uploads when authorising, and not when the page is reloaded and the session is still valid.

How do I stop this initial duplicate upload?

Please Help
  • 929
  • 1
  • 8
  • 11
  • did you 1st make sure your `$OAUTH2_CLIENT_ID` and `$OAUTH2_CLIENT_SECRET` are set, valid and recognized by the google API ? – OldPadawan Apr 14 '17 at 17:49
  • yes....if they weren't how would the video upload in the first place ??? – Please Help Apr 14 '17 at 18:07
  • I did not go through all google API :), just checking it was not put on hold while you authorize, then, it might upload twice... – OldPadawan Apr 14 '17 at 18:09
  • 1
    well since no one wanted to help me, I did it using a filthy method of putting the $videopath in a txt, and then it will break out the try block if the same $videopath is detected in the txt. This is not nice. Please send help. Where are you google engineers – Please Help Apr 14 '17 at 20:03

2 Answers2

5

You can use the following code to upload the file just after user has signin when user click a submit button with the path defined in a text input :

<?php
/**
 * Library Requirements
 *
 * 1. Install composer (https://getcomposer.org)
 * 2. On the command line, change to this directory (api-samples/php)
 * 3. Require the google/apiclient library
 *    $ composer require google/apiclient:~2.0
 */
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
  throw new \Exception('please run "composer require google/apiclient:~2.0" in "' . __DIR__ .'"');
}
require_once __DIR__ . '/vendor/autoload.php';
session_start();

$response = "";

/*
 * You can acquire an OAuth 2.0 client ID and client secret from the
 * {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
 * For more information about using OAuth 2.0 to access Google APIs, please see:
 * <https://developers.google.com/youtube/v3/guides/authentication>
 * Please ensure that you have enabled the YouTube Data API for your project.
 */
$OAUTH2_CLIENT_ID = 'YOUR_CLIENTID';
$OAUTH2_CLIENT_SECRET = 'YOUR_CLIENT_SECRET';

$client = new Google_Client();
$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);
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
// Check if an auth token exists for the required scopes
$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])) {
  $client->setAccessToken($_SESSION[$tokenSessionKey]);
}
// Check to ensure that the access token was successfully acquired.

if ($client->getAccessToken()) {
  try {

    $videoPath = "";

    if (isset($_GET['videoPath'])){
    $videoPath = $_GET['videoPath'];
    }
    else if(isset($_SESSION['videoPath'])){
      $videoPath = $_SESSION['videoPath'];
    }

    if(isset($videoPath) && !isset($_GET['state']) && file_exists($videoPath)) {

      // 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("Test title");
      $snippet->setDescription("Test description");
      $snippet->setTags(array("tag1", "tag2"));

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

      // 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);

      // 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);

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

      $response .= '</ul>';

      $_SESSION['path'] = "";
  }
  else{
    $response = "no path was specified or file doesn't exist";
    file_put_contents('php://stderr', print_r("no path was specified or file doesn't exist", TRUE));
  }

  } catch (Google_Service_Exception $e) {
    $response = htmlspecialchars($e->getMessage());
  } catch (Google_Exception $e) {
    $response = htmlspecialchars($e->getMessage());
  }
  $_SESSION[$tokenSessionKey] = $client->getAccessToken();
} else {

  if(isset($_GET['videoPath'])){

    $_SESSION["videoPath"] = $_GET['videoPath'];

    // If the user hasn't authorized the app, initiate the OAuth flow
    $state = mt_rand();
    $client->setState($state);
    $_SESSION['state'] = $state;
    $authUrl = $client->createAuthUrl();
    header('Location: ' . $authUrl);
  }
}
?>

<!doctype html>
<html>
<head>
 <title>Upload Video</title>
</head>
<body>
   <div>
        <form id="form" action="resumable_upload.php"">

          <label>Enter the path to the video to upload
           :
                <input id="video-path" name="videoPath" value='/path/to/video' type="text" />
          </label>
          <input name="action" type="submit" value="Upload video" />
        </form>
        <div id="playlist-container">
          <?php echo $response ?>
        </div>
    </div>
</body>
</html>

But if the page gets refreshed or if the user clicks the button by mistake one more time, it will re-upload the video. Check this post to deal with the duplicated video issue

danronmoon
  • 3,814
  • 5
  • 34
  • 56
Bertrand Martel
  • 42,756
  • 16
  • 135
  • 159
-1

I know this question is old but this is a issue I was struggling with for a while.

In my situation, I had a form that needed to pass values to my upload script, and if a user wasn't signed in then the post values would get lost during the sign in process. So I came up with a way using session variables.

First towards the start of my script I set a variable to count the 'page' views -

// set the session views
if (!isset($_SESSION['views'])) {
    $_SESSION['views'] = 0;
}

// every view increments
$_SESSION['views'] = $_SESSION['views'] + 1;

Then I stored session variables.

        // If the user hasn't authorized the app, initiate the OAuth flow
        $state = mt_rand();
        $client->setState($state);
        $_SESSION['state'] = $state;

        $authorID   = $_POST['a_id'];
        $videoTitle = $_POST['ytu_title'];

        // Set session variables
        $vidID  = $_POST['vid_id'];
        $_SESSION["author"] = $_POST['a_id'];
        $_SESSION["title"]  = $_POST['ytu_title'];
        $_SESSION["video"] = $vidID;

Then I put an if statement to check the views before uploading -

// if its on the third view or more
if ($_SESSION['views'] >= 3) {
    // 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($_SESSION["title"]);
                $snippet->setDescription("Youtube Video.");
                $snippet->setTags(array(
                    "test",
                    "test 2"
                ));
    // and rest of the upload part from upload php script
    // etc etc

                // 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);

    } // closing if statement

I was finally able to fix my issue with the if statement before uploading.

730wavy
  • 944
  • 1
  • 19
  • 57