LINUX.ORG.RU

Как отправить zip через XMLHttpRequest?

 , , , ,


0

1

Здравствуйте.

Есть проблемка:)

Делаю zip в хроме с помощью вот этой либы https://stuk.github.io/jszip/

Далее, надо отправить этот zip на сервер. Делаю это с помощью XMLHttpRequest c POST multipart/form-data. Описано тут.

Но приходит на сервер не бинарный файл, а текст.

При этом, если я сохраняю этот архив на жесткий диск,


location = "data:application/zip;base64," + myZip

то сохраняется нормально, открывается анзипом.

Пробовал разные входные данные, и текст, и bufferarray uint8array, все равно на выхлопе текст.

Подскажите пожалуйста, как это решить.

Спасибо.

Вокруг тебя нет телепатов!

Где код? Вывод хидеров, которые получает сервер, где?

--

Телепатия в действии:

https://stuk.github.io/jszip/documentation/limitations.html

If you load the file from an ajax call, ask your XHR an ArrayBuffer. Loading a string is asking for troubles.

If you want to get the content of an ASCII file as a string, consider using asBinary() instead of asText(). The transformation «binary string» -> «unicode string» is a consuming process.

gh0stwizard ★★★★★ ()
Ответ на: Вокруг тебя нет телепатов! от gh0stwizard

прошу прощения, что задержался.

Приблизительно вот такой код


<html>
<head>
</head>

<body>


<script src="jszip.min.js"></script>

<script>


getImageAsArrayBuffer = function(url){
  return new Promise(function(resolve){ 
   with(new XMLHttpRequest){
      responseType = "arraybuffer"
      open("GET", url, true)
      onload = function(event){
         resolve(new Uint8Array(response))
      }
      send()
   }
 })
}

getImageAsText = function(url){
  return new Promise(function(resolve){ 
   with(new XMLHttpRequest){
      open("GET", url, true)
      onreadystatechange = function(){
       if(status == 200 && readyState == 4) resolve(responseText)
      }
      send()
   }
 })
}


genString = function(){ return String(Math.random()).slice(2)}
genBoundary = function(){ return "WebKitFormBoundary" + genString() }
genFileName = function(){ return '"' + genString() + '.zip"'}


Request = {
  
  body: null, 

  create: function(data, fileContent){
    var o = Object.create(this)
    o.data = data
    o.fileContent = fileContent
    return o
  },

  createFileData: function(){
    return 'Content-Disposition: form-data; name="file"; filename=' + genFileName() + '\r\nContent-Type: application/zip\r\n\r\n' + this.fileContent + '\r\n'
  },
   
  createBody: function(){
      var boundary = genBoundary()
      var boundaryMiddle = "------" + boundary + "\r\n"
      var boundaryLast = "------" + boundary + "--\r\n"
      
      var body = ["\r\n"]
      for(var i in this.data){
        if(!this.data.hasOwnProperty(i)) break
        body.push('Content-Disposition: form-data; name="' + i + '"\r\n\r\n' + this.data[i] + '\r\n')
      }
      this.body = body.join(boundaryMiddle) + boundaryMiddle + this.createFileData() + boundaryLast
  },

  send: function(){
       with(new XMLHttpRequest){
         open("POST", "test")
         onreadystatechange = function(){
           if(status == 200 && readyState == 4) console.log(responseText)
         }
         send(this.body)
       }
  }, 

}


getImageAsText("images/original.jpg")
 .then(function(data){
    var zip = new JSZip()
    zip.file("test.jpg", data)
    var request = Request.create({foo: 1, bar: 2}, zip.generate())
    request.createBody()
    request.send()
})



getImageAsArrayBuffer("images/original.jpg")
 .then(function(data){
    var zip = new JSZip()
    zip.file("test.jpg", data)
    var request = Request.create({foo: 1, bar: 2}, zip.generate())
    request.createBody()
    request.send()
})



</script>

</body>
</html>

Вот что приходит от первого запроса (asText)

POST /test HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 9396
Origin: http://localhost:8888
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Referer: http://localhost:8888/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8


------WebKitFormBoundary6984594215173274
Content-Disposition: form-data; name="foo"

1
------WebKitFormBoundary6984594215173274
Content-Disposition: form-data; name="bar"

2
------WebKitFormBoundary6984594215173274
Content-Disposition: form-data; name="file"; filename="40402030176483095.zip"
Content-Type: application/zip

UEsDBAoAAAAAABa0U0dF5xu38xkAAPMZAAAIAAAAdGVzdC5qcGfvv73vv73vv73vv70AEEpGSUYAAQEAAAEAAQAA77+977+9AD5DUkVBVE9SOiBnZC1qcGVnIHYxLjAgKHVzaW5nIElKRyBKUEVHIHY4MCksIGRlZmF1bHQgcXVhbGl0eQrvv73vv70AQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZ

тут еще каракули

77+9WO+/ve+/ve+/vVnvv70R77+977+977+977+9MVQ+77+977+977+9ee+/vTZJ77+977+9UEsBAhQACgAAAAAAFrRTR0XnG7fzGQAA8xkAAAgAAAAAAAAAAAAAAAAAAAAAAHRlc3QuanBnUEsFBgAAAAABAAEANgAAABkaAAAAAA==
------WebKitFormBoundary6984594215173274--

Вот что со второго (asArray)

------WebKitFormBoundary34400912607088685
Content-Disposition: form-data; name="foo"

1
------WebKitFormBoundary34400912607088685
Content-Disposition: form-data; name="bar"

2
------WebKitFormBoundary34400912607088685
Content-Disposition: form-data; name="file"; filename="28930457727983594.zip"
Content-Type: application/zip

UEsDBAoAAAAAAKq0U0d4FO5WWQ4AAFkOAAAIAAAAdGVzdC5qcGf/2P/gABBK

тут еще каракули

a2kTqUkUe2UNey2N1cW0UWSreblj7GrcdRqWh0mqTG0s5rlXOIYnkP4DNfMcsxXczElupr3bxXeSp4WvpFYjMDqR9eP614HJzcIvvk/hT2FJkgVxFjv3+tZsxG85q/PMVQ+9ZbHec02Sf/ZUEsBAhQACgAAAAAAqrRTR3gU7lZZDgAAWQ4AAAgAAAAAAAAAAAAAAAAAAAAAAHRlc3QuanBnUEsFBgAAAAABAAEANgAAAH8OAAAAAA==
------WebKitFormBoundary34400912607088685--
newquestion ()
Ответ на: комментарий от newquestion

во втором куске заголовки не скопироал

POST /test HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 5440
Origin: http://localhost:8888
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Referer: http://localhost:8888/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8

//fixed

newquestion ()
Ответ на: комментарий от newquestion

С твоим кодом (который выложил без правок), по идее все нормально.

Сервер у тебя какой используется? То, что у тебя прилетает сервер должен раскодировать по base64 обратно, получив байты. Ну, а дальше открыть файл на запись и записать результат.

gh0stwizard ★★★★★ ()
Ответ на: комментарий от gh0stwizard

Я сейчас тестирую на своем локальном сервере, и у себя я могу просто выдрть этот кусок и делать что хочу, это не проблема, а тот сервер, на который я отсылать это должен, толком не знаю, у меня сейчас есть только 2 файла от него. Он не принимает этот вариант, пишет, что не может разархивировать. В этом проблема, или в чем-то другом, я не знаю. Но у меня возникло подозрение, потому что в принципе, в этот multipart/form-data вообще-то, бинарные файлы пишуться, я пробовал с картинкой. Логично было бы предположить, что и с зипом так же должно быть. Вот файл, на который «по настоящему» отсылается запрос

<?php
/**
 * upload.php
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

#!! IMPORTANT: 
#!! this file is just an example, it doesn't incorporate any security checks and 
#!! is not recommended to be used in production environment as it is. Be sure to 
#!! revise it and customize to your needs.


// Make sure file is not cached (as it happens for example on iOS devices)
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

/* 
// Support CORS
header("Access-Control-Allow-Origin: *");
// other CORS headers if any...
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
	exit; // finish preflight CORS requests here
}
*/

// 5 minutes execution time
@set_time_limit(5 * 60);

// Uncomment this one to fake upload time
// usleep(5000);

// Settings
$targetDir = "tmp";
$extractDir = "tmp" . DIRECTORY_SEPARATOR . "extracted";
//$targetDir = 'uploads';
$cleanupTargetDir = true; // Remove old files
$maxFileAge = 5 * 3600; // Temp file age in seconds


// Create target dir
if (!file_exists($targetDir)) {
	@mkdir($targetDir);
}

$subject = $_REQUEST["subject"];
$cat = $_REQUEST["cat"];
$geo = $_REQUEST["geo"];
$url = $_REQUEST["url"];
$mob = $_REQUEST["mob"];
$desk = $_REQUEST["desk"];
//echo $subject;

// Get a file name
if (isset($_REQUEST["name"])) {
	$fileName = $_REQUEST["name"];
} elseif (!empty($_FILES)) {
	$fileName = $_FILES["file"]["name"];
} else {
	$fileName = uniqid("file_");
}

$filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;

// Chunking might be enabled
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0;


// Remove old temp files	
if ($cleanupTargetDir) {
	if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
		die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
	}

	while (($file = readdir($dir)) !== false) {
		$tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;

		// If temp file is current file proceed to the next
		if ($tmpfilePath == "{$filePath}.part") {
			continue;
		}

		// Remove temp file if it is older than the max age and is not the current file
		if (preg_match('/\.part$/', $file) && (filemtime($tmpfilePath) < time() - $maxFileAge)) {
			@unlink($tmpfilePath);
		}
	}
	closedir($dir);
}	


// Open temp file
if (!$out = @fopen("{$filePath}.part", $chunks ? "ab" : "wb")) {
	die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
}

if (!empty($_FILES)) {
	if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
		die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
	}

	// Read binary input stream and append it to temp file
	if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
		die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
	}
} else {	
	if (!$in = @fopen("php://input", "rb")) {
		die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
	}
}

while ($buff = fread($in, 4096)) {
	fwrite($out, $buff);
}

@fclose($out);
@fclose($in);

// Check if file has been uploaded
if (!$chunks || $chunk == $chunks - 1) {
	// Strip the temp .part suffix off 
	rename("{$filePath}.part", $filePath);

	$zip = new ZipArchive();
	if ($zip->open($filePath) === TRUE) {
    	$zip->extractTo($extractDir);
    	$zip->close();
    	unlink($filePath);
	}
	else
		die('{"jsonrpc" : "2.0", "error" : {"code": 104, "message": "Failed to extract archive."}, "id" : "id"}');

	$tizers = glob($extractDir. DIRECTORY_SEPARATOR ."*.{jpg,png,gif,jpeg}", GLOB_BRACE);

    $hosted = dirname(__FILE__). DIRECTORY_SEPARATOR ."tizers";
    $hosted_image_names = array();
    foreach ($tizers as $tizer) {

    	$new_tizer_name = '';
    	$not_found = true;
    	while($not_found){
    		$characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
		    $randomString = '';
		    for ($i = 0; $i < 4; $i++) {
		        $randomString .= $characters[rand(0, strlen($characters) - 1)];
		    }
	        if(!file_exists($hosted. DIRECTORY_SEPARATOR .$randomString)){
	            $new_tizer_name = $randomString;
	            $not_found = false;
	        }

	    }

        $new_path = $hosted. DIRECTORY_SEPARATOR .$new_tizer_name;
        rename($tizer,$new_path);
        array_push($hosted_image_names, $new_tizer_name);
    }

    $db = new Database();
    foreach ($hosted_image_names as $t_name)
    {
    	$db->create_tizer($t_name,$subject,$cat,$geo,$url,$mob,$desk);
    }


	
}

// Return Success JSON-RPC response
die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');



class Database
{

    private $dbh = null;
    public function __construct()
    {   
        $username = "zewlad_tz33";
        $password = "pO90ID7x";
        $hostname = "localhost";

        try {
            $this->dbh = new PDO("mysql:host=$hostname;dbname=zewlad_tz33;charset=utf8", $username, $password);
        } catch (PDOException $e) {
            print "Error!: " . $e->getMessage() . "<br/>";
            die();
        }
    }

    public function create_tizer($tizer_name,$subject,$cat,$geo,$url,$mob,$desk)
    {   
    	$state = 0;
    	$ts = time();

        $stmt = $this->dbh->prepare("INSERT INTO tizers (name,bot_text,cat_id,geo,sub_id,state,ts,is_mobile,is_desktop) VALUES (:name,:url,:cat_id,:geo,:sub_id,:state,:ts,:mob,:desk)");                               
        $stmt->bindParam(':name', $tizer_name, PDO::PARAM_STR);
        $stmt->bindParam(':url', $url, PDO::PARAM_STR);
        $stmt->bindParam(':cat_id', $cat, PDO::PARAM_INT);
        $stmt->bindParam(':geo', $geo, PDO::PARAM_STR);
        $stmt->bindParam(':sub_id', $subject, PDO::PARAM_INT);
        $stmt->bindParam(':state', $state, PDO::PARAM_INT);
        $stmt->bindParam(':ts', $ts, PDO::PARAM_INT);
        $stmt->bindParam(':mob', $mob, PDO::PARAM_INT);
        $stmt->bindParam(':desk', $desk, PDO::PARAM_INT);
        $stmt->execute();                                 
    }

}

Я в PHP, к сожалению, дуб, поэтому запарюсь я там разбираться:)

newquestion ()
Ответ на: комментарий от ichi404

Я вообще то в этих бинарных делах почти ноль, но надо что-то делать, поэтому, я мог бы поэксперементировать, хотя бы методом тыка. Есть какие-то предложения?

newquestion ()

простыни кода в треде детектед

заворачивай их куда-то с подсветкой синтаксиса (типа на paste.ubuntu.com), это тебе не платная техподдержка

reprimand ★★★★★ ()
Ответ на: комментарий от newquestion

Вот тебе предложение: почитай про base64, узнай как преобразовать его в байты на твоей платформе и делай что ты там хотел.

ichi404 ()
Ответ на: комментарий от ichi404

мне это все надо сделать средствами хрома, я пишу плагин. Если бы я мог задействовать операционную систему, проблем бы не было. Даже в этом варианте, как я написал, если сохранить этот архив на хард, с помощью location = "data:application/zip;base64," + myZip он становиться нормальным архивом. А вот если отправлять по сети, отправляется текстом почему-то.

newquestion ()
Ответ на: комментарий от newquestion

Приходит строка «[object Blob]»

И что, ни на какую мысль это тебя не наводит?

Короче просто выкини свою фигню (ты там эволюцинными методами кодить учишься?) и сделай по-человечески. https://developer.mozilla.org/en-US/docs/Web/API/FormData

ya-betmen ★★★★★ ()
Последнее исправление: ya-betmen (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.