如何通过javascript / php存储和发送$ _FILES

时间:2012-08-28 07:41:42

标签: php jquery file youtube multipartform-data

我正在尝试设置一个可以同时上传到YouTube和Vimeo的表单。我更喜欢使用Posterous.com这样的东西,但由于他们已经被Twitter收购,他们的帮助团队已经从地球上掉下来,因为我的电子邮件现在没有得到回复(他们删除了一堆服务) )...

所以无论如何,这就是youtube进程应该如何工作:

  1. 通过网络表单
  2. 设置要上传的视频的标题和类别
  3. 提交表单,从youtube获取访问令牌
  4. 生成另一个表单,允许您选择要上传的文件
  5. 提交表单,访问令牌和文件已发送,youtube上传视频
  6. 我想要做的是使用拖放上传器将其转变为一步:

    1. 将文件拖放到页面
    2. javascript抓取文件信息,将文件名设置为视频标题并使用默认类别
    3. javascript调用php并发送文件名&类别到youtube,获取访问令牌并创建带文件输入的表单
    4. 获取令牌后,发送一个POST(通过PHP)请求,文件上传存储在会话变量中(此时我必须再次选择该文件并单击提交)
    5. 我不应该能够使用第一步中的文件信息,将其存储在会话变量中并通过php以编程方式提交令牌和文件信息吗?我不知道如何发送这些数据,就像它作为表单提交一样发送,我并不总是从youtube上获取响应代码来修复我的代码。

      这可能是我需要的答案:sending xml and headers via curl但我不知道如何设置$xmlString$videoData

      EDIT ::

      我想我需要通过PHP而不是javascript来做这件事,因为我正在尝试修改以下代码:

      /**
       * Create upload form by sending the incoming video meta-data to youtube and
       * retrieving a new entry. Prints form HTML to page.
       *
       * @param string $VideoTitle The title for the video entry.
       * @param string $VideoDescription The description for the video entry.
       * @param string $VideoCategory The category for the video entry.
       * @param string $nextUrl (optional) The URL to redirect back to after form upload has completed.
       * @return void
       */
      
      function createUploadForm($videoTitle, $videoCategory, $nextUrl = null) {
      $httpClient = getAuthSubHttpClient();
      $youTubeService = new Zend_Gdata_YouTube($httpClient);
      $newVideoEntry = new Zend_Gdata_YouTube_VideoEntry();
      
      $newVideoEntry->setVideoTitle($videoTitle);
      
      //make sure first character in category is capitalized
      $videoCategory = strtoupper(substr($videoCategory, 0, 1))
          . substr($videoCategory, 1);
      $newVideoEntry->setVideoCategory($videoCategory);
      
      // convert videoTags from whitespace separated into comma separated
      
      $tokenHandlerUrl = 'https://gdata.youtube.com/action/GetUploadToken';
      try {
          $tokenArray = $youTubeService->getFormUploadToken($newVideoEntry, $tokenHandlerUrl);
          if (loggingEnabled()) {
              logMessage($httpClient->getLastRequest(), 'request');
              logMessage($httpClient->getLastResponse()->getBody(), 'response');
          }
      } catch (Zend_Gdata_App_HttpException $httpException) {
          print 'ERROR ' . $httpException->getMessage()
              . ' HTTP details<br /><textarea cols="100" rows="20">'
              . $httpException->getRawResponseBody()
              . '</textarea><br />'
              . '<a href="session_details.php">'
              . 'click here to view details of last request</a><br />';
          return;
      } catch (Zend_Gdata_App_Exception $e) {
          print 'ERROR - Could not retrieve token for syndicated upload. '
              . $e->getMessage()
              . '<br /><a href="session_details.php">'
              . 'click here to view details of last request</a><br />';
          return;
      }
      
      $tokenValue = $tokenArray['token'];
      $postUrl = $tokenArray['url'];
      
      // place to redirect user after upload
      if (!$nextUrl) {
          $nextUrl = $_SESSION['homeUrl'];
      } 
      
      //instead of echoing the form below, send $_FILES from previous form submit
      
      print <<< END
          <br />      
      
          <form id="uploadToYouTubeForm" action="${postUrl}?nexturl=${nextUrl}" method="post" enctype="multipart/form-data">
          <input id="uploadToYouTube" name="file" type="file" />
          <input name="token" type="hidden" value="${tokenValue}"/>
          <input value="Upload Video File" type="submit" />
          </form>
      
      END;
      }
      

1 个答案:

答案 0 :(得分:0)

我想我可能有一个解决方案。以下是我想要使用的表格:

<!--removing the action ensures form will be sent via javascript, then when that request comes back, I can add in the authenticated youtube URL needed-->
<form id="upload" action="" method="POST" enctype="multipart/form-data" class="form-horizontal"><!--upload.php-->
  <fieldset>
    <legend><h1>Video File Upload</h1></legend>
    <input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="1000000000" /> <!--1GB-->
    <p id="filedrag">Drag and drop a video file from your computer here. Or use the 'File upload' button below.</p><!--dragFileHere-->
    <label class="control-label" for="fileselect">Files to upload:</label>
    <input type="file" id="fileselect" name="fileselect[]" /> <!--multiple="multiple"-->
    <button class="btn" id="submitbutton" type="submit">Upload Files</button> <!--hidden via js/css-->
    <div class="progress progress-striped active">
      <div class="bar" style="width: 0%;"></div>
    </div>
    <label class="hide" for="video-title">Title</label>
    <input type="text" id="video-title" class="span4" placeholder="Video Title"/>
    <label class="control-label" for="video-category">Category</label>
    <select id="video-category" name="videoCategory" class="span4">
      <option value="Autos">Autos &amp; Vehicles</option>
      <option value="Music">Music</option>
      .......
      <option value="Entertainment" selected>Entertainment</option>
    </select>
    <input id="token" type="text" placeholder="token"/> <!--will be hidden-->
</div>
</fieldset>
</form>

将action属性留空,(并使用我已有的脚本来响应用户交互)我可以确保通过javascript以编程方式提交表单:

<script src=http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js></script>
<script src=_js/video_app.js" type="text/javascript></script>
<script>
  /*
  filedrag.js - HTML5 File Drag & Drop demonstration
  Featured on SitePoint.com
  Developed by Craig Buckler (@craigbuckler) of OptimalWorks.net (without jQuery)
  */

  // output information
  function Output(msg) {
    $('#messages').html(msg + $('#messages').html());
  }

  // file drag hover
  function FileDragHover(e) {
    e.stopPropagation();
    e.preventDefault();
    $(this).addClass("hover");
  } 

  function FileDragOut(e) {
    $(this).removeClass("hover");
  }

  // file selection
  function FileSelectHandler(e) {
    // cancel event and hover styling
    FileDragHover(e);

    // fetch FileList object
    var files = e.target.files || e.dataTransfer.files;
    // process all File objects
    for (var i = 0, f; f = files[i]; i++) {
      ParseFile(f); //prints file data to div and optionally displays content of selected file
      UploadFile(f); //uploads file to server
    }
  }

  // output file information
  function ParseFile(file) {
    videoName = file.name;
    videoType = file.type;
    videoURL = "http://localhost/"+videoName;
    videoCategory = $('#video-category').val();

    Output(
      "</strong> type: <strong>" + file.type +
      "</strong> size: <strong>" + file.size +
      "</strong> bytes</p>"
    );

    // sets a default value because a title is needed for youtube to send response  
    if( $('#video-title').val() == $('#video-title').attr('placeholder') ) {
      $('#video-title').val(videoName);
    }

    var reader = new FileReader();
    reader.onload = function(e) {

      var fileContents = e.target.result;

      Output(
        '<img src="'+e.target.result+'"/>'
      );
    }
    reader.readAsDataURL(file);

    //get upload token
    ytVideoApp.prepareSyndicatedUpload(videoName, videoCategory);
  }

  // upload video files
  function UploadFile(file) {       
    var xhr = new XMLHttpRequest();
    if (xhr.upload && file.size <= $('#MAX_FILE_SIZE').val()) { //&& file.type == "video/mp4" or video/*
      xhr.upload.addEventListener("progress", function(e) {
        var pc = Math.ceil(e.loaded / e.total * 100);
      }, false);
      // file received/failed
      xhr.onreadystatechange = function(e) {
        if (xhr.readyState == 4) {
          if(xhr.status == 200) { //success

          } else { //fail  

          }
        }
      };
      // start upload
      xhr.open("POST", 'upload.php', true); //$("#upload").attr('action')
      xhr.setRequestHeader("X_FILENAME", file.name);
      xhr.send(file);
    }
  }

  // initialize
  function Init() {
    // file select
    $('#fileselect').change(FileSelectHandler);
    // is XHR2 available?
    var xhr = new XMLHttpRequest();
    if (xhr.upload) {
      // file drop
      $('#filedrag').bind('dragover', FileDragHover);
      $('#filedrag').bind('dragleave', FileDragOut);

      //I can't get the below line to work, so I've used the ugly fallback
      //$('#filedrag').bind('drop', FileSelectHandler);
      document.getElementById('filedrag').addEventListener("drop", FileSelectHandler, false);           

      filedrag.style.display = "block";
      // remove submit button
      submitbutton.style.display = "none";
    }
  }
  // call initialization file
  if (window.File && window.FileList && window.FileReader) {
    Init();
  }
</script>

_js / video_app.js:

/**
* Zend Framework
* @package    Zend_Gdata
....
/**
* provides namespacing for the YouTube Video Application PHP version (ytVideoApp)
**/
var ytVideoApp = {};
/**
* Sends an AJAX request to the server to retrieve a list of videos or
* the video player/metadata.  Sends the request to the specified filePath
* on the same host, passing the specified params, and filling the specified
* resultDivName with the resutls upon success.
* @param {String} filePath The path to which the request should be sent
* @param {String} params The URL encoded POST params
* @param {String} resultDivName The name of the DIV used to hold the results
*/
ytVideoApp.sendRequest = function(filePath, params, resultDivName) {
  if (window.XMLHttpRequest) {
    var xmlhr = new XMLHttpRequest();
  } else {
    var xmlhr = new ActiveXObject('MSXML2.XMLHTTP.3.0');
  }

  xmlhr.open('POST', filePath);
  xmlhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 

  xmlhr.onreadystatechange = function() {
    var resultDiv = document.getElementById(resultDivName);
    if (xmlhr.readyState == 1) {
      resultDiv.innerHTML = '<b>Loading...</b>'; 
    } else if (xmlhr.readyState == 4 && xmlhr.status == 200) {
      if (xmlhr.responseText) {
        resultDiv.innerHTML = xmlhr.responseText;
      }
    } else if (xmlhr.readyState == 4) {
      alert('Invalid response received - Status: ' + xmlhr.status);
    }
  }
  xmlhr.send(params);
}


ytVideoApp.prepareSyndicatedUpload = function(videoTitle, videoCategory, fileContents) {    
  var filePath = '_scripts/operations.php';
  var params = 'operation=create_upload_form' +
    '&videoTitle=' + videoTitle +
    '&videoCategory=' + videoCategory;
  ytVideoApp.sendRequest(filePath, params, ytVideoApp.SYNDICATED_UPLOAD_DIV);
}

_scripts / operations.php:

require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_YouTube');
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
Zend_Loader::loadClass('Zend_Gdata_App_Exception');
/*
 * The main controller logic.
 *
 * POST used for all authenticated requests
 * otherwise use GET for retrieve and supplementary values
 */
session_start();
setLogging('on');
generateUrlInformation();

if (!isset($_POST['operation'])) {
  // if a GET variable is set then process the token upgrade
  if (isset($_GET['token'])) {
    updateAuthSubToken($_GET['token']);
  } else {
    if (loggingEnabled()) {
      logMessage('reached operations.php without $_POST or $_GET variables set', 'error');
      header('Location: add-content.php');
    }
  }
}

$operation = $_POST['operation'];

switch ($operation) {
  ....
  case 'create_upload_form':
    createUploadForm($_POST['videoTitle'],
                     $_POST['videoCategory'],
                     $_POST['videoContents']);
  break;
  ....
  default:
    unsupportedOperation($_POST);
  break;
}

function createUploadForm($videoTitle, $videoCategory, $nextUrl = null) {
  $httpClient = getAuthSubHttpClient();
  $youTubeService = new Zend_Gdata_YouTube($httpClient);
  $newVideoEntry = new Zend_Gdata_YouTube_VideoEntry();

  $newVideoEntry->setVideoTitle($videoTitle);

  //make sure first character in category is capitalized
  $videoCategory = strtoupper(substr($videoCategory, 0, 1))
                              . substr($videoCategory, 1);
  $newVideoEntry->setVideoCategory($videoCategory);

  // convert videoTags from whitespace separated into comma separated
  $tokenHandlerUrl = 'https://gdata.youtube.com/action/GetUploadToken';
  try {
    $tokenArray = $youTubeService->getFormUploadToken($newVideoEntry, $tokenHandlerUrl);
    if (loggingEnabled()) {
      logMessage($httpClient->getLastRequest(), 'request');
      logMessage($httpClient->getLastResponse()->getBody(), 'response');
    }
  } catch (Zend_Gdata_App_HttpException $httpException) {
    print 'ERROR ' . $httpException->getMessage()
                   . ' HTTP details<br /><textarea cols="100" rows="20">'
                   . $httpException->getRawResponseBody()
                   . '</textarea><br />'
                   . '<a href="session_details.php">'
                   . 'click here to view details of last request</a><br />';
    return;
  } catch (Zend_Gdata_App_Exception $e) {
    print 'ERROR - Could not retrieve token for syndicated upload. '
                 . $e->getMessage()
                 . '<br /><a href="session_details.php">'
                 . 'click here to view details of last request</a><br />';
    return;
  }
  $tokenValue = $tokenArray['token'];
  $postUrl = $tokenArray['url'];
  // place to redirect user after upload
  if (!$nextUrl) {
    $nextUrl = $_SESSION['homeUrl'];
  }

  //instead of outputting the form below, send variables (json???) to be interpreted by xmlhr in _js/video_app.js
  //print <<< END
  //<br />      
  //<p>url: ${postUrl}?nexturl=${nextUrl}</p>
  //<form id="uploadToYouTubeForm" action="temp.php" method="post" enctype="multipart/form-data">
  //<input id="uploadToYouTube" name="file" type="file" onchange="autoUploadToYouTube();" /><br/>
  //token: <input id="token" name="token" type="text" value="${tokenValue}"/><br/>
  //<input value="Manual upload" type="submit" />
  //</form>     
  //END;
  //}

所以第一个javascript会监听拖动&amp;输入类型=“文件”的drop(在div上)或change()事件。表单实际上并未提交,但是数据被收集并通过ajax发送到php脚本,该脚本返回上传所需的令牌和URL。然后,原始PHP脚本输出一个表单来选择文件(以及包含令牌的隐藏字段)。 INSTEAD,我想将url和token作为变量传递,并使用XMLHttpRequest将这些变量放在表单的action属性中,并将键设置为隐藏的输入字段的值。然后,该字段可以通过$('#uploadToYouTubeForm').submit();

提交

可能出现的唯一问题是向youtube应用发送其他信息,我希望它会忽略它,或者我可能需要以编程方式删除youtube不接受的字段(标题,类别,最大文件大小) )......