ios - example - Subir archivo con parámetros usando Alamofire
alamofire swift 4 (11)
Estoy intentando cargar un archivo usando
Alamofire
.
La carga funciona bien cuando se usa un archivo (
NSUrl
), sin embargo, ¿no puedo entender cómo usar la opción
NSData
?
Esto es lo que tengo como prueba:
var url:NSURL = NSURL.URLWithString("http://localhost:8080/bike.jpeg")
var err: NSError?
var imageData :NSData = NSData.dataWithContentsOfURL(url,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)
Alamofire.upload(.POST, "http://localhost:8080/rest/service/upload/test.png", imageData)
.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
println(totalBytesWritten)
}
.responseJSON { (request, response, JSON, error) in
println(request)
println(response)
println(JSON)
}
¿Recibo un código de estado 415?
Además, ¿cómo puedo enviar parámetros adicionales en la carga?
Gracias
EDITAR
No estaba configurando el tipo de contenido correcto:
var manager = Manager.sharedInstance
manager.session.configuration.HTTPAdditionalHeaders = ["Content-Type": "application/octet-stream"]
let imageData: NSMutableData = NSMutableData.dataWithData(UIImageJPEGRepresentation(imageTest.image, 30));
Alamofire.upload(.POST, "http://localhost:8080/rest/service/upload?attachmentName=file.jpg", imageData)
.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
println(totalBytesWritten)
}
.responseString { (request, response, JSON, error) in
println(request)
println(response)
println(JSON)
}
Todavía no puedo entender cómo enviar parámetros adicionales junto con la carga.
A continuación se encuentran swift y el código Php
Código Swift -> Apple Swift versión 3.0.1 (swiftlang-800.0.58.6 clang-800.0.42.1) Objetivo: x86_64-apple-macosx10.9
class func upload(jsonObject: AnyObject , files : Array<Any>? = nil , completionHandler : CompletionBlock? = nil ,failureHandler : FailureBlock? = nil )
{
Alamofire.upload(multipartFormData:
{ (multipartFormData) in
if let filesO = files
{
for i in (filesO.enumerated())
{
let image = UIImage(named: "/(i.element)")
let data = UIImageJPEGRepresentation(image!, 1)!
multipartFormData.append(data, withName: "imgFiles[]" , fileName: "/( NSUUID().uuidString).jpeg" , mimeType: "image/jpeg")
// imgFiles[] give array in Php Side
// imgFiles will give string in PHP String
}
}
for (key, value) in jsonObject as! [String : String]
{
multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
}}
},
to:baseURL)
Código PHP para obtener parámetros y archivos
Aquí los parámetros se manejan en $ _Request
Y los archivos se manejan en $ _File
El formato en $ _Datos de archivo (matriz, diccionario o cadena) dependerá de la solicitud en el lado rápido, aquí vea esta línea en el código
multipartFormData.append (data, withName: "imgFiles []", fileName: "(NSUUID (). uuidString) .jpeg", mimeType: "image / jpeg")
en el lado Php withName: "imgFiles []" da una matriz de nombre, formato, tipo
P.ej
"nombre": ["06748B86-478E-421B-8470-6262755AC149.jpeg", "E70269E9-FB54-4BFD-B807-7E418C81540D.jpeg"], "tipo": ["image / jpeg", "image / jpeg" ], "tmp_name": ["/ tmp / phpz3UAPq", "/ tmp / phpCAPExG"], "error": [0,0], "size": [2779495,2067259]}
Código PHP
if (isset($_FILES[''imgFiles'']) and strlen($orderId) > 0) {
foreach ($_FILES[''imgFiles''][''tmp_name''] as $key => $tmp_name) {
$file_name = $key . $_FILES[''imgFiles''][''name''][$key];
$file_size = $_FILES[''imgFiles''][''size''][$key];
$file_tmp = $_FILES[''imgFiles''][''tmp_name''][$key];
$file_type = $_FILES[''imgFiles''][''type''][$key];
if (is_dir("$desired_dir/" . $file_name) == false) {
//move_uploaded_file($file_tmp, "user_data/" . $file_name);
move_uploaded_file($file_tmp, $desired_dir . "/" .
$file_name);
} else { //rename the file if another one exist
$new_dir = $desired_dir . "/" . $file_name . time();
rename($file_tmp, $new_dir);
}
Aquí hay una función simple que requiere la URL, parámetros e imageData de carga de destino y devuelve el URLRequestConvertible y NSData que Alamofire.upload requiere para cargar una imagen con parámetros.
// this function creates the required URLRequestConvertible and NSData we need to use Alamofire.upload
func urlRequestWithComponents(urlString:String, parameters:Dictionary<String, String>, imageData:NSData) -> (URLRequestConvertible, NSData) {
// create url request to send
var mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: urlString)!)
mutableURLRequest.HTTPMethod = Alamofire.Method.POST.rawValue
let boundaryConstant = "myRandomBoundary12345";
let contentType = "multipart/form-data;boundary="+boundaryConstant
mutableURLRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")
// create upload data to send
let uploadData = NSMutableData()
// add image
uploadData.appendData("/r/n--/(boundaryConstant)/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Disposition: form-data; name=/"file/"; filename=/"file.png/"/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Type: image/png/r/n/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData(imageData)
// add parameters
for (key, value) in parameters {
uploadData.appendData("/r/n--/(boundaryConstant)/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Disposition: form-data; name=/"/(key)/"/r/n/r/n/(value)".dataUsingEncoding(NSUTF8StringEncoding)!)
}
uploadData.appendData("/r/n--/(boundaryConstant)--/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
// return URLRequestConvertible and NSData
return (Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: nil).0, uploadData)
}
Aquí hay un ejemplo de cómo usarlo (vea CREAR Y ENVIAR SOLICITUD):
// init paramters Dictionary
var parameters = [
"task": "task",
"variable1": "var"
]
// add addtionial parameters
parameters["userId"] = "27"
parameters["body"] = "This is the body text."
// example image data
let image = UIImage(named: "177143.jpg")
let imageData = UIImagePNGRepresentation(image)
// CREATE AND SEND REQUEST ----------
let urlRequest = urlRequestWithComponents("http://example.com/uploadText/", parameters: parameters, imageData: imageData)
Alamofire.upload(urlRequest.0, urlRequest.1)
.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
println("/(totalBytesWritten) / /(totalBytesExpectedToWrite)")
}
.responseJSON { (request, response, JSON, error) in
println("REQUEST /(request)")
println("RESPONSE /(response)")
println("JSON /(JSON)")
println("ERROR /(error)")
}
Y si necesita el archivo php para la URL de destino (con una carpeta ''uploads'' en el mismo directorio):
// get picture variables
$file = $_FILES[''file''][''tmp_name''];
$fileName = $_FILES[''file''][''name''];
$fileType = $_FILES[''file''][''type''];
// check extension
$allowedExts = array("jpg", "jpeg", "png");
$rootName = reset(explode(".", $fileName));
$extension = end(explode(".", $fileName));
// create new file name
$time = time();
$newName = $rootName.$time.''.''.$extension;
// temporarily save file
$moved = move_uploaded_file($_FILES["file"]["tmp_name"], "uploads/".$newName );
if ($moved) $path = "uploads/".$newName;
$body = $_POST[''body''];
$userId = $_POST[''userId''];
$time = time();
if ($moved) {
$fullUrl = "http://antiblank.com/testPhotoUpload/".$path;
$arrayToSend = array(''status''=>''success'',''time''=>$time,''body''=>$body,''userId''=>$userId, "imageURL"=>$fullUrl);
} else {
$arrayToSend = array(''status''=>''FAILED'',''time''=>$time,''body''=>$body,''userId''=>$userId);
}
header(''Content-Type:application/json'');
echo json_encode($arrayToSend);
Aquí hay una solución que usa Alamofire 3.0 basada en la respuesta antiblanks:
let parameters = [
"par1": "value",
"par2": "value2"]
let URL = "YOUR_URL.php"
let image = UIImage(named: "image.png")
Alamofire.upload(.POST, URL, multipartFormData: {
multipartFormData in
if let _image = image {
if let imageData = UIImageJPEGRepresentation(_image, 0.5) {
multipartFormData.appendBodyPart(data: imageData, name: "file", fileName: "file.png", mimeType: "image/png")
}
}
for (key, value) in parameters {
multipartFormData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key)
}
}, encodingCompletion: {
encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseObject { (response: Response<UploadData, NSError>) -> Void in
switch response.result {
case .Success:
completionHandler?(success: true)
case .Failure(let error):
completionHandler?(success: false)
}
}
case .Failure(let encodingError):
print(encodingError)
}
})
Cargue fotos / archivos con parámetros y encabezados personalizados a través de Swift 3 y 4 y Alamofire 4
// import Alamofire
func uploadWithAlamofire() {
let image = UIImage(named: "bodrum")!
// define parameters
let parameters = [
"hometown": "yalikavak",
"living": "istanbul"
]
Alamofire.upload(multipartFormData: { multipartFormData in
if let imageData = UIImageJPEGRepresentation(image, 1) {
multipartFormData.append(imageData, withName: "file", fileName: "file.png", mimeType: "image/png")
}
for (key, value) in parameters {
multipartFormData.append((value?.data(using: .utf8))!, withName: key)
}}, to: "upload_url", method: .post, headers: ["Authorization": "auth_token"],
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.response { [weak self] response in
guard let strongSelf = self else {
return
}
debugPrint(response)
}
case .failure(let encodingError):
print("error:/(encodingError)")
}
})
}
a través de Swift 2 y Alamofire 3
// import Alamofire
func uploadWithAlamofire() {
let image = UIImage(named: "myImage")!
// define parameters
let parameters = [
"hometown": "yalikavak",
"living": "istanbul"
]
// Begin upload
Alamofire.upload(.POST, "upload_url",
// define your headers here
headers: ["Authorization": "auth_token"],
multipartFormData: { multipartFormData in
// import image to request
if let imageData = UIImageJPEGRepresentation(image, 1) {
multipartFormData.appendBodyPart(data: imageData, name: "file", fileName: "myImage.png", mimeType: "image/png")
}
// import parameters
for (key, value) in parameters {
multipartFormData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key)
}
}, // you can customise Threshold if you wish. This is the alamofire''s default value
encodingMemoryThreshold: Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .Failure(let encodingError):
print(encodingError)
}
})
}
El código en la respuesta de @ antiblank no estaba funcionando para mí. He realizado algunos cambios y está funcionando ahora:
func urlRequestWithComponents(urlString:String, parameters:NSDictionary) -> (URLRequestConvertible, NSData) {
// create url request to send
var mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: urlString)!)
mutableURLRequest.HTTPMethod = Alamofire.Method.POST.rawValue
//let boundaryConstant = "myRandomBoundary12345"
let boundaryConstant = "NET-POST-boundary-/(arc4random())-/(arc4random())"
let contentType = "multipart/form-data;boundary="+boundaryConstant
mutableURLRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")
// create upload data to send
let uploadData = NSMutableData()
// add parameters
for (key, value) in parameters {
uploadData.appendData("/r/n--/(boundaryConstant)/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
if value is NetData {
// add image
var postData = value as NetData
//uploadData.appendData("Content-Disposition: form-data; name=/"/(key)/"; filename=/"/(postData.filename)/"/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
// append content disposition
var filenameClause = " filename=/"/(postData.filename)/""
let contentDispositionString = "Content-Disposition: form-data; name=/"/(key)/";/(filenameClause)/r/n"
let contentDispositionData = contentDispositionString.dataUsingEncoding(NSUTF8StringEncoding)
uploadData.appendData(contentDispositionData!)
// append content type
//uploadData.appendData("Content-Type: image/png/r/n/r/n".dataUsingEncoding(NSUTF8StringEncoding)!) // mark this.
let contentTypeString = "Content-Type: /(postData.mimeType.getString())/r/n/r/n"
let contentTypeData = contentTypeString.dataUsingEncoding(NSUTF8StringEncoding)
uploadData.appendData(contentTypeData!)
uploadData.appendData(postData.data)
}else{
uploadData.appendData("Content-Disposition: form-data; name=/"/(key)/"/r/n/r/n/(value)".dataUsingEncoding(NSUTF8StringEncoding)!)
}
}
uploadData.appendData("/r/n--/(boundaryConstant)--/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
// return URLRequestConvertible and NSData
return (Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: nil).0, uploadData)
}
UTILIZAR:
let docDir:AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let imagePath = docDir + "/myPic.jpg"
var imageData = NSData(contentsOfFile: imagePath, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: nil)
var parameters = [
"pic" :NetData(nsData: imageData!, filename: "customName.jpg"),
"otherParm" :"Value"
]
let urlRequest = self.urlRequestWithComponents("http://www.example.com/upload.php", parameters: parameters)
El NetData de https://github.com/nghialv/Net/blob/master/Net/NetData.swift
Código upload.php:
<?php
// In PHP versions earlier than 4.1.0, $HTTP_POST_FILES should be used instead
// of $_FILES.
$uploaddir = ''uploads/'';
// PS: custom filed name : pic
$uploadfile = $uploaddir . basename($_FILES[''pic''][''name'']);
if (move_uploaded_file($_FILES[''pic''][''tmp_name''], $uploadfile)) {
$array = array ("code" => "1", "message" => "successfully");
} else {
$array = array ("code" => "0", "message" => "Possible file upload attack!".$_FILES[''pic''][''name'']);
}
echo json_encode ( $array );
?>
La carga multiparte está programada para incluirse con la próxima versión (1.3.0) de Alamofire. Mientras tanto, utilizando la información de este hilo, he creado una clase que simplifica la carga de archivos e incluye parámetros adicionales ("entradas" regulares) en la solicitud junto con uno o más archivos. Sin suponer que los archivos son de un tipo particular o el uso de enrutadores.
FileUploader.swift:
import Foundation
import Alamofire
private struct FileUploadInfo {
var name:String
var mimeType:String
var fileName:String
var url:NSURL?
var data:NSData?
init( name: String, withFileURL url: NSURL, withMimeType mimeType: String? = nil ) {
self.name = name
self.url = url
self.fileName = name
self.mimeType = "application/octet-stream"
if mimeType != nil {
self.mimeType = mimeType!
}
if let _name = url.lastPathComponent {
fileName = _name
}
if mimeType == nil, let _extension = url.pathExtension {
switch _extension.lowercaseString {
case "jpeg", "jpg":
self.mimeType = "image/jpeg"
case "png":
self.mimeType = "image/png"
default:
self.mimeType = "application/octet-stream"
}
}
}
init( name: String, withData data: NSData, withMimeType mimeType: String ) {
self.name = name
self.data = data
self.fileName = name
self.mimeType = mimeType
}
}
class FileUploader {
private var parameters = [String:String]()
private var files = [FileUploadInfo]()
private var headers = [String:String]()
func setValue( value: String, forParameter parameter: String ) {
parameters[parameter] = value
}
func setValue( value: String, forHeader header: String ) {
headers[header] = value
}
func addParametersFrom( #map: [String:String] ) {
for (key,value) in map {
parameters[key] = value
}
}
func addHeadersFrom( #map: [String:String] ) {
for (key,value) in map {
headers[key] = value
}
}
func addFileURL( url: NSURL, withName name: String, withMimeType mimeType:String? = nil ) {
files.append( FileUploadInfo( name: name, withFileURL: url, withMimeType: mimeType ) )
}
func addFileData( data: NSData, withName name: String, withMimeType mimeType:String = "application/octet-stream" ) {
files.append( FileUploadInfo( name: name, withData: data, withMimeType: mimeType ) )
}
func uploadFile( request sourceRequest: NSURLRequest ) -> Request? {
var request = sourceRequest.mutableCopy() as! NSMutableURLRequest
let boundary = "FileUploader-boundary-/(arc4random())-/(arc4random())"
request.setValue( "multipart/form-data;boundary=/(boundary)", forHTTPHeaderField: "Content-Type")
let data = NSMutableData()
for (name, value) in headers {
request.setValue(value, forHTTPHeaderField: name)
}
// Amazon S3 (probably others) wont take parameters after files, so we put them first
for (key, value) in parameters {
data.appendData("/r/n--/(boundary)/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
data.appendData("Content-Disposition: form-data; name=/"/(key)/"/r/n/r/n/(value)".dataUsingEncoding(NSUTF8StringEncoding)!)
}
for fileUploadInfo in files {
data.appendData( "/r/n--/(boundary)/r/n".dataUsingEncoding(NSUTF8StringEncoding)! )
data.appendData( "Content-Disposition: form-data; name=/"/(fileUploadInfo.name)/"; filename=/"/(fileUploadInfo.fileName)/"/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
data.appendData( "Content-Type: /(fileUploadInfo.mimeType)/r/n/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
if fileUploadInfo.data != nil {
data.appendData( fileUploadInfo.data! )
}
else if fileUploadInfo.url != nil, let fileData = NSData(contentsOfURL: fileUploadInfo.url!) {
data.appendData( fileData )
}
else { // ToDo: report error
return nil
}
}
data.appendData("/r/n--/(boundary)--/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
return Alamofire.upload( request, data )
}
}
Se usaría así:
// This example uploads a file called example.png found in the app resources
let fileURL = NSBundle.mainBundle().URLForResource("example", withExtension: "png")
let fileUploader = FileUploader()
// we can add multiple files
// this would be equivalent to: <input type="file" name="myFile"/>
fileUploader.addFileURL(fileURL!, withName: "myFile")
// we can add NSData objects directly
let data = UIImage(named: "sample")
fileUploader.addFileData( UIImageJPEGRepresentation(data,0.8), withName: "mySecondFile", withMimeType: "image/jpeg" )
// we can also add multiple aditional parameters
// this would be equivalent to: <input type="hidden" name="folderName" value="sample"/>
fileUploader.setValue( "sample", forParameter: "folderName" )
// put your server URL here
var request = NSMutableURLRequest( URL: NSURL(string: "http://myserver.com/uploadFile" )! )
request.HTTPMethod = "POST"
fileUploader.uploadFile(request: request)
Compruébelo o descárguelo de esta esencia: https://gist.github.com/ncerezo/b1991f8dfac01cb162c0
Mejorando la respuesta de EdFunke para Swift 2.2 Alamofire 3.3.1
Alamofire.upload(.POST, urlString, multipartFormData: {
multipartFormData in
if let _image = self.profilePic.image {
if let imageData = UIImagePNGRepresentation(_image) {
multipartFormData.appendBodyPart(data: imageData, name: "user_image", fileName: "file.png", mimeType: "image/png")
}
}
for (key, value) in userInfo {
multipartFormData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key)
}
}, encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .Failure(let encodingError):
print(encodingError)
}
}
)
Obtendrá 415 debido a que falta el tipo de contenido en su solicitud. A continuación se muestra una muestra completa de carga de imágenes en Swift 2 y AlamoFire
import UIKit
import Alamofire
class ViewController: UIViewController {
@IBOutlet var imageView: UIImageView!
@IBOutlet var btnUpload: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
func successDataHandler(responseData:String){
print ("IMAGE UPLOAD SUCCESSFUL !!!")
}
func failureDataHandler(errorData:String){
print (" !!! IMAGE UPLOAD FAILURE !!! ")
}
@IBAction func actionUpload(sender: AnyObject) {
let URL = "http://m8coreapibeta.azurewebsites.net/api/cards/SaveImages"
let postDataProlife:[String:AnyObject] = ["CardId":(dataCardDetail?.userId)!,"ImageType":1,"ImageData":imageView.image!]
uplaodImageData(URL, postData: postDataProlife, successHandler: successDataHandler, failureHandler: failureDataHandler)
}
func uplaodImageData(RequestURL: String,postData:[String:AnyObject]?,successHandler: (String) -> (),failureHandler: (String) -> ()) -> () {
let headerData:[String : String] = ["Content-Type":"application/json"]
Alamofire.request(.POST,RequestURL, parameters: postData, encoding: .URLEncodedInURL, headers: headerData).responseString{ response in
switch response.result {
case .Success:
print(response.response?.statusCode)
successHandler(response.result.value!)
case .Failure(let error):
failureHandler("/(error)")
}
}
}
}
Si bien hay otras respuestas que aconsejan cómo construir manualmente solicitudes multiparte, es posible que solo desee seguir con AFNetworking. Aunque está escrito en Objective-C, aún puede usarlo en sus proyectos Swift (consulte Swift y Objective-C en el mismo proyecto ). De todos modos, el código Swift para enviar una solicitud multiparte usando AFNetworking es el siguiente:
let data = UIImagePNGRepresentation(image)
let manager = AFHTTPSessionManager()
manager.POST(uploadURLString, parameters: nil, constructingBodyWithBlock: { formData in
formData.appendPartWithFileData(data, name: "image", fileName: "test.png", mimeType: "image/png")
}, success: { operation, responseObject in
println(responseObject)
}) { operation, error in
println(error)
}
Xcode molesto tiene problemas para reconocer este parámetro
id<AFMultipartFormData>
,
formData
, por lo que no disfruta la finalización típica del código del editor del método
appendPartWithFileData
o sus parámetros, pero cuando lo compila y lo ejecuta, funciona bien.
Tomé la respuesta de antiblank y envolví todo esto en 1 función con el controlador de finalización. Pensé que podría ser útil para alguien. Es un poco más áspero que la respuesta de antiblank, ya que simplemente estoy tomando una respuesta de cadena del archivo PHP (no JSON).
Así es como lo llamas:
let imageData = UIImagePNGRepresentation(myImageView.image)
uploadImage("http://www.example.com/image_upload.php", imageData: imageData, subdir: "images", filename: "imageID.png")
{ (req, res, str, err) -> Void in
// do whatever you want to to for error handling and handeling success
}
Aquí está la función en sí:
func uploadImage(urlToPHPFile: String, imageData: NSData, subdir: String, filename: String, completionHandler:(request:NSURLRequest, response:NSURLResponse?, responseString:String?, error: NSError?) -> ()) {
func urlRequestWithComponents(urlString:String, parameters:Dictionary<String, String>, imageData:NSData) -> (URLRequestConvertible, NSData) {
// create url request to send
var mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: urlString)!)
mutableURLRequest.HTTPMethod = Method.POST.rawValue
let boundaryConstant = "myRandomBoundary12345";
let contentType = "multipart/form-data;boundary="+boundaryConstant
mutableURLRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")
// create upload data to send
let uploadData = NSMutableData()
// add image
uploadData.appendData("/r/n--/(boundaryConstant)/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Disposition: form-data; name=/"file/"; filename=/"file.png/"/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Type: image/png/r/n/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData(imageData)
// add parameters
for (key, value) in parameters {
uploadData.appendData("/r/n--/(boundaryConstant)/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Disposition: form-data; name=/"/(key)/"/r/n/r/n/(value)".dataUsingEncoding(NSUTF8StringEncoding)!)
}
uploadData.appendData("/r/n--/(boundaryConstant)--/r/n".dataUsingEncoding(NSUTF8StringEncoding)!)
// return URLRequestConvertible and NSData
return (ParameterEncoding.URL.encode(mutableURLRequest, parameters: nil).0, uploadData)
}
let parameters = [
"subdir" : subdir,
"filename": filename
]
let urlRequest = urlRequestWithComponents(urlToPHPFile, parameters, imageData)
AlamoFire.upload(urlRequest.0, urlRequest.1)
.responseString(completionHandler: { [weak self] (req, res, str, err) -> Void in
if let strongSelf = self {
completionHandler(request: req, response: res, responseString: str, error: err)
}
}
)
}
Y aquí está el archivo php.
$subdir = $_POST[''subdir''];
$filename = $_POST["filename"];
$targetPath = $subdir.''/''.$filename;
$moved = move_uploaded_file($_FILES["file"]["tmp_name"], $targetPath );
if ($moved) {
echo "OK";
}
else {
echo "Error: file not uploaded";
}
Versión más corta basada en respuestas @antiblank y @VincentYan.
Clase
class Photo {
class func upload(image: UIImage, filename: String) -> Request {
let route = Router.CreatePhoto()
var request = route.URLRequest.mutableCopy() as NSMutableURLRequest
let boundary = "NET-POST-boundary-/(arc4random())-/(arc4random())"
request.setValue("multipart/form-data;boundary="+boundary,
forHTTPHeaderField: "Content-Type")
let parameters = NSMutableData()
for s in ["/r/n--/(boundary)/r/n",
"Content-Disposition: form-data; name=/"photos[photo]/";" +
" filename=/"/(filename)/"/r/n",
"Content-Type: image/png/r/n/r/n"] {
parameters.appendData(s.dataUsingEncoding(NSUTF8StringEncoding)!)
}
parameters.appendData(UIImageJPEGRepresentation(image, 1))
parameters.appendData("/r/n--/(boundary)--/r/n"
.dataUsingEncoding(NSUTF8StringEncoding)!)
return Alamofire.upload(request, parameters)
}
}
Uso
let rep = (asset as ALAsset).defaultRepresentation()
let ref = rep.fullResolutionImage().takeUnretainedValue()
Photo.upload(UIImage(CGImage: ref)!, filename: rep.filename())
.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
println(totalBytesWritten)
}
.responseJSON { (request, response, JSON, error) in
println(JSON)
}