我想我可能有一个解决方案。以下是我要使用的表格:
<!--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 & 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 侦听输入 type="file" 的拖放(在 div 上)或 change() 事件。表单实际上并未提交,而是收集数据并通过 ajax 发送到 php 脚本,该脚本返回上传所需的令牌和 url。然后,原始 PHP 脚本会输出一个表单来选择文件(以及一个包含令牌的隐藏字段)。相反,我想将 url 和 token 作为变量传递,并使用 XMLHttpRequest 将这些变量放入表单的 action 属性中,并将键设置为隐藏输入字段的值。然后可以通过以下方式提交该字段$('#uploadToYouTubeForm').submit();
可能出现的唯一问题是将附加信息发送到 youtube 应用程序,我希望它会简单地忽略它,或者我可能需要以编程方式删除 youtube 不接受的字段(标题、类别、最大文件大小).. ..