所以我一直在試圖讓Chunked上傳爲我一直在努力的項目工作,事實上我是新手,事實上,對於所有密集的目的,您可以認爲我是一個自學的完整noob,我使用網站上的手動上載模板和傳統服務器端示例文件來了解代碼如何工作並嘗試將它們拼合在一起成爲一個全功能的示例,供我構建。我已經能夠獲得大部分工作。在Fine-Uploader中上傳文件,無法在成功上傳後合併/合併塊
我已經成功地將常規文件上傳到文件夾成功,如果我上傳文件沒有分塊它進入我的文件目錄,但是如果我使用chunking它的作品來大塊文件並將其上傳到一個文件夾在我的Chunks目錄,但我似乎無法弄清楚如何讓它把大塊放回到一起,並將其放在文件目錄中
我的Firefox控制檯給了我這個響應,並在完成上傳文件後停止不管我的代碼中是否包含我的分塊成功端點,這使我認爲這與我的分塊成功端點沒有正確設置或與這些線條有關。
[Fine Uploader 5.11.8] All chunks have been uploaded for 0 - finalizing....fine-uploader.js:162:21
[Fine Uploader 5.11.8] Received response status 200 with body: {"success":true,"uuid":"79e7db33-9609-49cd-bcb1-2606bea6abd7","uploadName":null}fine-uploader.js:162:21
[Fine Uploader 5.11.8] Finalize successful for 0
我花了大約2天無濟於事研究這個,我似乎並沒有被收到錯誤,但正如我所說,我幾乎是一個菜鳥,當涉及到理解這個對我自己。任何幫助是極大的讚賞。
這是我上傳的代碼本體
<body>
<!-- Fine Uploader DOM Element
====================================================================== -->
<div id="fine-uploader-manual-trigger"></div>
<!-- Your code to create an instance of Fine Uploader and bind to the DOM/template
====================================================================== -->
<script>
var manualUploader = new qq.FineUploader({
debug: true,
element: document.getElementById('fine-uploader-manual-trigger'),
template: 'qq-template-manual-trigger',
request: {
endpoint: 'endpoint.php'
},
chunking: {
enabled: true
},
success: {
endpoint: "endpoint.php?done"
},
resume: {
enabled: true
},
thumbnails: {
placeholders: {
waitingPath: 'images/waiting-generic.png',
notAvailablePath: 'images/not_available-generic.png'
}
},
autoUpload: false,
showMessage: function(message) { //show message if any error occur during upload process
alert(message);
}
});
qq(document.getElementById("trigger-upload")).attach("click", function() {
manualUploader.uploadStoredFiles();
});
</script>
</body>
</html>
這裏是我的Endpoint.php
require_once "handler.php";
$uploader = new UploadHandler();
// Specify the list of valid extensions, ex. array("jpeg", "xml", "bmp")
$uploader->allowedExtensions = array(); // all files types allowed by default
// Specify max file size in bytes.
$uploader->sizeLimit = null;
// Specify the input name set in the javascript.
$uploader->inputName = "qqfile"; // matches Fine Uploader's default inputName value by default
// If you want to use the chunking/resume feature, specify the folder to temporarily save parts.
$uploader->chunksFolder = "chunks";
$method = $_SERVER["REQUEST_METHOD"];
if ($method == "POST") {
header("Content-Type: text/plain");
// Assumes you have a chunking.success.endpoint set to point here with a query parameter of "done".
// For example: /myserver/handlers/endpoint.php?done
if (isset($_GET["done"])) {
$result = $uploader->combineChunks("files");
}
// Handles upload requests
else {
// Call handleUpload() with the name of the folder, relative to PHP's getcwd()
$result = $uploader->handleUpload("files");
// To return a name used for uploaded file you can use the following line.
$result["uploadName"] = $uploader->getUploadName();
}
echo json_encode($result);
}
// for delete file requests
else if ($method == "DELETE") {
$result = $uploader->handleDelete("files");
echo json_encode($result);
}
else {
header("HTTP/1.0 405 Method Not Allowed");
}
?>
這裏是我的handler.php文件,我只是使用默認的傳統服務器端示例文件。
class UploadHandler {
public $allowedExtensions = array();
public $sizeLimit = null;
public $inputName = 'qqfile';
public $chunksFolder = 'chunks';
public $chunksCleanupProbability = 0.001; // Once in 1000 requests on avg
public $chunksExpireIn = 604800; // One week
protected $uploadName;
/**
* Get the original filename
*/
public function getName(){
if (isset($_REQUEST['qqfilename']))
return $_REQUEST['qqfilename'];
if (isset($_FILES[$this->inputName]))
return $_FILES[$this->inputName]['name'];
}
public function getInitialFiles() {
$initialFiles = array();
for ($i = 0; $i < 5000; $i++) {
array_push($initialFiles, array("name" => "name" + $i, uuid => "uuid" + $i, thumbnailUrl => ""));
}
return $initialFiles;
}
/**
* Get the name of the uploaded file
*/
public function getUploadName(){
return $this->uploadName;
}
public function combineChunks($uploadDirectory, $name = null) {
$uuid = $_POST['qquuid'];
if ($name === null){
$name = $this->getName();
}
$targetFolder = $this->chunksFolder.DIRECTORY_SEPARATOR.$uuid;
$totalParts = isset($_REQUEST['qqtotalparts']) ? (int)$_REQUEST['qqtotalparts'] : 1;
$targetPath = join(DIRECTORY_SEPARATOR, array($uploadDirectory, $uuid, $name));
$this->uploadName = $name;
if (!file_exists($targetPath)){
mkdir(dirname($targetPath), 0777, true);
}
$target = fopen($targetPath, 'wb');
for ($i=0; $i<$totalParts; $i++){
$chunk = fopen($targetFolder.DIRECTORY_SEPARATOR.$i, "rb");
stream_copy_to_stream($chunk, $target);
fclose($chunk);
}
// Success
fclose($target);
for ($i=0; $i<$totalParts; $i++){
unlink($targetFolder.DIRECTORY_SEPARATOR.$i);
}
rmdir($targetFolder);
if (!is_null($this->sizeLimit) && filesize($targetPath) > $this->sizeLimit) {
unlink($targetPath);
http_response_code(413);
return array("success" => false, "uuid" => $uuid, "preventRetry" => true);
}
return array("success" => true, "uuid" => $uuid);
}
/**
* Process the upload.
* @param string $uploadDirectory Target directory.
* @param string $name Overwrites the name of the file.
*/
public function handleUpload($uploadDirectory, $name = null){
if (is_writable($this->chunksFolder) &&
1 == mt_rand(1, 1/$this->chunksCleanupProbability)){
// Run garbage collection
$this->cleanupChunks();
}
// Check that the max upload size specified in class configuration does not
// exceed size allowed by server config
if ($this->toBytes(ini_get('post_max_size')) < $this->sizeLimit ||
$this->toBytes(ini_get('upload_max_filesize')) < $this->sizeLimit){
$neededRequestSize = max(1, $this->sizeLimit/1024/1024) . 'M';
return array('error'=>"Server error. Increase post_max_size and upload_max_filesize to ".$neededRequestSize);
}
if ($this->isInaccessible($uploadDirectory)){
return array('error' => "Server error. Uploads directory isn't writable");
}
$type = $_SERVER['CONTENT_TYPE'];
if (isset($_SERVER['HTTP_CONTENT_TYPE'])) {
$type = $_SERVER['HTTP_CONTENT_TYPE'];
}
if(!isset($type)) {
return array('error' => "No files were uploaded.");
} else if (strpos(strtolower($type), 'multipart/') !== 0){
return array('error' => "Server error. Not a multipart request. Please set forceMultipart to default value (true).");
}
// Get size and name
$file = $_FILES[$this->inputName];
$size = $file['size'];
if (isset($_REQUEST['qqtotalfilesize'])) {
$size = $_REQUEST['qqtotalfilesize'];
}
if ($name === null){
$name = $this->getName();
}
// check file error
if($file['error']) {
return array('error' => 'Upload Error #'.$file['error']);
}
// Validate name
if ($name === null || $name === ''){
return array('error' => 'File name empty.');
}
// Validate file size
if ($size == 0){
return array('error' => 'File is empty.');
}
if (!is_null($this->sizeLimit) && $size > $this->sizeLimit) {
return array('error' => 'File is too large.', 'preventRetry' => true);
}
// Validate file extension
$pathinfo = pathinfo($name);
$ext = isset($pathinfo['extension']) ? $pathinfo['extension'] : '';
if($this->allowedExtensions && !in_array(strtolower($ext), array_map("strtolower", $this->allowedExtensions))){
$these = implode(', ', $this->allowedExtensions);
return array('error' => 'File has an invalid extension, it should be one of '. $these . '.');
}
// Save a chunk
$totalParts = isset($_REQUEST['qqtotalparts']) ? (int)$_REQUEST['qqtotalparts'] : 1;
$uuid = $_REQUEST['qquuid'];
if ($totalParts > 1){
# chunked upload
$chunksFolder = $this->chunksFolder;
$partIndex = (int)$_REQUEST['qqpartindex'];
if (!is_writable($chunksFolder) && !is_executable($uploadDirectory)){
return array('error' => "Server error. Chunks directory isn't writable or executable.");
}
$targetFolder = $this->chunksFolder.DIRECTORY_SEPARATOR.$uuid;
if (!file_exists($targetFolder)){
mkdir($targetFolder, 0777, true);
}
$target = $targetFolder.'/'.$partIndex;
$success = move_uploaded_file($_FILES[$this->inputName]['tmp_name'], $target);
return array("success" => true, "uuid" => $uuid);
}
else {
# non-chunked upload
$target = join(DIRECTORY_SEPARATOR, array($uploadDirectory, $uuid, $name));
if ($target){
$this->uploadName = basename($target);
if (!is_dir(dirname($target))){
mkdir(dirname($target), 0777, true);
}
if (move_uploaded_file($file['tmp_name'], $target)){
return array('success'=> true, "uuid" => $uuid);
}
}
return array('error'=> 'Could not save uploaded file.' .
'The upload was cancelled, or server error encountered');
}
}
/**
* Process a delete.
* @param string $uploadDirectory Target directory.
* @params string $name Overwrites the name of the file.
*
*/
public function handleDelete($uploadDirectory, $name=null)
{
if ($this->isInaccessible($uploadDirectory)) {
return array('error' => "Server error. Uploads directory isn't writable" . ((!$this->isWindows()) ? " or executable." : "."));
}
$targetFolder = $uploadDirectory;
$url = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$tokens = explode('/', $url);
$uuid = $tokens[sizeof($tokens)-1];
$target = join(DIRECTORY_SEPARATOR, array($targetFolder, $uuid));
if (is_dir($target)){
$this->removeDir($target);
return array("success" => true, "uuid" => $uuid);
} else {
return array("success" => false,
"error" => "File not found! Unable to delete.".$url,
"path" => $uuid
);
}
}
/**
* Returns a path to use with this upload. Check that the name does not exist,
* and appends a suffix otherwise.
* @param string $uploadDirectory Target directory
* @param string $filename The name of the file to use.
*/
protected function getUniqueTargetPath($uploadDirectory, $filename)
{
// Allow only one process at the time to get a unique file name, otherwise
// if multiple people would upload a file with the same name at the same time
// only the latest would be saved.
if (function_exists('sem_acquire')){
$lock = sem_get(ftok(__FILE__, 'u'));
sem_acquire($lock);
}
$pathinfo = pathinfo($filename);
$base = $pathinfo['filename'];
$ext = isset($pathinfo['extension']) ? $pathinfo['extension'] : '';
$ext = $ext == '' ? $ext : '.' . $ext;
$unique = $base;
$suffix = 0;
// Get unique file name for the file, by appending random suffix.
while (file_exists($uploadDirectory . DIRECTORY_SEPARATOR . $unique . $ext)){
$suffix += rand(1, 999);
$unique = $base.'-'.$suffix;
}
$result = $uploadDirectory . DIRECTORY_SEPARATOR . $unique . $ext;
// Create an empty target file
if (!touch($result)){
// Failed
$result = false;
}
if (function_exists('sem_acquire')){
sem_release($lock);
}
return $result;
}
/**
* Deletes all file parts in the chunks folder for files uploaded
* more than chunksExpireIn seconds ago
*/
protected function cleanupChunks(){
foreach (scandir($this->chunksFolder) as $item){
if ($item == "." || $item == "..")
continue;
$path = $this->chunksFolder.DIRECTORY_SEPARATOR.$item;
if (!is_dir($path))
continue;
if (time() - filemtime($path) > $this->chunksExpireIn){
$this->removeDir($path);
}
}
}
/**
* Removes a directory and all files contained inside
* @param string $dir
*/
protected function removeDir($dir){
foreach (scandir($dir) as $item){
if ($item == "." || $item == "..")
continue;
if (is_dir($item)){
$this->removeDir($item);
} else {
unlink(join(DIRECTORY_SEPARATOR, array($dir, $item)));
}
}
rmdir($dir);
}
/**
* Converts a given size with units to bytes.
* @param string $str
*/
protected function toBytes($str){
$val = trim($str);
$last = strtolower($str[strlen($str)-1]);
switch($last) {
case 'g': $val *= 1024;
case 'm': $val *= 1024;
case 'k': $val *= 1024;
}
return $val;
}
/**
* Determines whether a directory can be accessed.
*
* is_executable() is not reliable on Windows prior PHP 5.0.0
* (http://www.php.net/manual/en/function.is-executable.php)
* The following tests if the current OS is Windows and if so, merely
* checks if the folder is writable;
* otherwise, it checks additionally for executable status (like before).
*
* @param string $directory The target directory to test access
*/
protected function isInaccessible($directory) {
$isWin = $this->isWindows();
$folderInaccessible = ($isWin) ? !is_writable($directory) : (!is_writable($directory) && !is_executable($directory));
return $folderInaccessible;
}
/**
* Determines is the OS is Windows or not
*
* @return boolean
*/
protected function isWindows() {
$isWin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
return $isWin;
}
}
只是說「它不起作用」,不足以提供幫助。什麼_specifically_出錯了?你看到了什麼症狀?什麼日誌消息進一步說明了這個問題?此外,這裏包含的代碼不完整。試圖處理上傳和組合塊的代碼在哪裏? –
我的歉意,對於所有密集的目的,我幾乎是一個小白這個,沒有意識到我忘了包括我的Handler.php,我編輯了我的問題,包括它,我的firefox控制檯響應成功的分塊上傳,並試圖讓我的問題更清楚一些,請讓我知道如何讓事情變得更容易理解,如果還有什麼我錯過了,那將有利於包括在內。基本上我不知道如何讓分塊文件在成功上傳後合併回來,這讓我覺得我沒有正確設置我的分塊成功端點 – GrandStar
看起來你的文件沒有問題。 –