我在获得一些代码时遇到了一些麻烦,我对 php/html 的经验充其量是"有限的",所以我希望我问这个看起来不像一个菜鸟。
我遇到的问题是无法将小图像上传到网络服务器。在过去的 4-5 个小时里,我一直在玩以下内容,在英国已经快凌晨 2 点了,我取得的唯一进展是改变了
[NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
自
[NSString stringWithFormat:@"enctype='"multipart/form-data'"; boundary=%@",boundary];
这使我的服务器在每次发送内容时停止给出内部错误。
代码在下面,它在这个网站的许多页面上,我找不到原作者来给予信用。当我在接收 php 文件中print_r($_FILES);
时,我当前得到一个空数组。
任何帮助将不胜感激,提前感谢。
NSString *urlString = @"http://mysite/upload_image.php";
UIImage * img = [UIImage imageNamed:@"mypic.png"];
NSData *imageData = UIImageJPEGRepresentation(img, 90);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ;
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];
NSString *boundary = @"---------------------------14737809831466499882746641449";
NSString *contentType = [NSString stringWithFormat:@"enctype='"multipart/form-data'"; boundary=%@",boundary];
[request addValue:contentType forHTTPHeaderField: @"Content-Type"];
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:@"'r'n--%@'r'n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Disposition: attachment; name='"image'"; filename='"davesfile.jpg'"'r'n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: application/octet-stream'r'n'r'n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:imageData]];
[body appendData:[[NSString stringWithFormat:@"'r'n--%@--'r'n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSLog(@"%@",returnString);
几个反应:
-
如果您使用 AFNetworking,则创建这些类型的请求的过程会更简单,让您摆脱自己构建请求的杂草:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.responseSerializer = [AFHTTPResponseSerializer serializer]; [manager POST:[url absoluteString] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { [formData appendPartWithFileData:imageData name:fieldName fileName:[imagePath lastPathComponent] mimeType:[self mimeTypeForPath:imagePath]]; } success:^(AFHTTPRequestOperation *operation, id responseObject) { NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]; NSLog(@"Success: %@", string); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }];
-
顺便说一下,我通常使用MobileCoreServices.framework在扩展的基础上获取mime类型,而不是硬编码它:
- (NSString *)mimeTypeForPath:(NSString *)path { // get a mime type for an extension using MobileCoreServices.framework CFStringRef extension = (__bridge CFStringRef)[path pathExtension]; CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL); assert(UTI != NULL); NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType)); assert(mimetype != NULL); CFRelease(UTI); return mimetype; }
-
我注意到您正在将图像检索到
UIImage
中,然后使用UIImageJPEGRepresentation
来获取NSData
。如果您愿意或必须这样做,请执行此操作,但我通常更喜欢发送原始数据,直接绕过通过UIImage
的往返,这可能会引入图像降级和元数据丢失。相反,您可能希望直接获取NSData
:NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"mypic" ofType:@"png"]; // note, I'm going back to bundle, not grabbing `UIImage` from imageview NSData *imageData = [NSData dataWithContentsOfFile:imagePath];
如果你真的必须通过
UIImage
进行往返,那么你可能想要使用imageWithContentsOfFile
而不是imageNamed
,因为后者会不必要地缓存图像。 -
如果您决定自己创建请求,这是我过去使用的例程:
- (void)uploadFileAtPath:(NSString *)imagePath forField:(NSString *)fieldName URL:(NSURL*)url parameters:(NSDictionary *)parameters { NSString *filename = [imagePath lastPathComponent]; NSData *imageData = [NSData dataWithContentsOfFile:imagePath]; NSMutableData *httpBody = [NSMutableData data]; NSString *boundary = [self generateBoundaryString]; NSString *mimetype = [self mimeTypeForPath:imagePath]; // configure the request NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; [request setHTTPShouldHandleCookies:NO]; [request setTimeoutInterval:30]; [request setHTTPMethod:@"POST"]; // set content type NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; [request setValue:contentType forHTTPHeaderField: @"Content-Type"]; // add params (all params are strings) [parameters enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) { [httpBody appendData:[[NSString stringWithFormat:@"--%@'r'n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name='"%@'"'r'n'r'n", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]]; [httpBody appendData:[[NSString stringWithFormat:@"%@'r'n", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]]; }]; // add image data if (imageData) { [httpBody appendData:[[NSString stringWithFormat:@"--%@'r'n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name='"%@'"; filename='"%@'"'r'n", fieldName, filename] dataUsingEncoding:NSUTF8StringEncoding]]; [httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@'r'n'r'n", mimetype] dataUsingEncoding:NSUTF8StringEncoding]]; [httpBody appendData:imageData]; [httpBody appendData:[@"'r'n" dataUsingEncoding:NSUTF8StringEncoding]]; } [httpBody appendData:[[NSString stringWithFormat:@"--%@--'r'n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; // setting the body of the post to the reqeust [request setHTTPBody:httpBody]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { if (connectionError) { NSLog(@"sendAsynchronousRequest error=%@", connectionError); return; } NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"Success: %@", string); }]; }
显然,如果您没有使用任何
parameters
(您似乎没有这样做),则可以为该参数传递nil
。但关键是,如果需要,它支持其他参数。我还使用异步网络请求,因为永远不应该在主队列上发出同步网络请求。这使用 Apple 的 SimpleURLConnections 示例中的
generateBoundaryString
方法:- (NSString *)generateBoundaryString { // generate boundary string // // adapted from http://developer.apple.com/library/ios/#samplecode/SimpleURLConnections // // Note in iOS 6 and later, you can just: // // return [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]]; CFUUIDRef uuid; NSString *uuidStr; uuid = CFUUIDCreate(NULL); assert(uuid != NULL); uuidStr = CFBridgingRelease(CFUUIDCreateString(NULL, uuid)); assert(uuidStr != NULL); CFRelease(uuid); return [NSString stringWithFormat:@"Boundary-%@", uuidStr]; }
-
如果您愿意,我以上面的一些代码为模型改装了您的代码:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; [request setHTTPMethod:@"POST"]; NSString *boundary = @"---------------------------14737809831466499882746641449"; NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; [request addValue:contentType forHTTPHeaderField: @"Content-Type"]; NSMutableData *body = [NSMutableData data]; [body appendData:[[NSString stringWithFormat:@"--%@'r'n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name='"%@'"; filename='"%@'"'r'n", fieldName, [imagePath lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"Content-Type: %@'r'n'r'n", [self mimeTypeForPath:imagePath]] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[NSData dataWithData:imageData]]; [body appendData:[[NSString stringWithFormat:@"'r'n--%@--'r'n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [request setHTTPBody:body]; NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; NSLog(@"%@",returnString);
-
就个人而言,我建议更改PHP代码以生成JSON响应(因为这会使您的应用程序更容易使用)。
顺便说一下,我已经用我的PHP代码测试了上述内容。如果您仍然遇到问题,我建议您也与我们分享您的PHP代码,因为格式良好的请求的构造与PHP代码的要求密切相关。