我正在构建一个客户端 - 服务器应用程序,其中应用程序正在发送包含大量图像的zip文件,并且php服务器应检查文件是否已收到并返回zip文件中的图像数量发送。
这是应用程序中的代码:
NSData *zipData = [[NSData alloc] initWithContentsOfFile:zipFile]; // zipFile contains the zip file path
NSString *postLength = [NSString stringWithFormat:@"%d", [zipData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:@"http://localhost/test.php"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:zipData];
NSHTTPURLResponse* urlResponse = nil;
NSError *error = [[NSError alloc] init];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
NSString *result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(@"Response Code: %d", [urlResponse statusCode]);
if ([urlResponse statusCode] >= 200 && [urlResponse statusCode] < 300)
{
NSLog(@"Response: %@", result);
}
这是我的php文件,使用xampp在本地主机上运行:
<?php
print_r($_POST);
print_r($_FILES);
?>
使用sethttpbody将zip文件附加到请求中,我正在尝试查看php中的文件,如上所示,但它始终为空,请帮助我,而且是通过以下方式查看发送的zip文件的权利打印$ _POST和$ _FILES如果没有正确的方法,zip文件转换为NSDATA,我也检查了连接已建立,但我真的很困惑。
答案 0 :(得分:1)
您的Objective-C代码存在问题,您将Content-Type
标头定义为application/x-www-form-urlencoded
,但请求正文与Content-Type
不一致。从理论上讲,您可以编写处理构造请求的PHP代码(读取正文的原始数据),但最好更改请求以符合既定标准。
如果您自己编写代码来构造这样的请求,那就有点难看了(请参阅本答案的结尾),所以我建议使用AFNetworking,这极大地简化了这些请求的创建: / p>
NSData *zipData = [NSData dataWithContentsOfFile:zipFile];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:urlString parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:zipData name:@"file" fileName:[zipFile lastPathComponent] mimeType:@"application/zip"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
BOOL success = [responseObject[@"success"] boolValue];
NSString *errorMessage = responseObject[@"error"];
NSLog(@"Success: %d; Error message: %@", success, errorMessage);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
注意,这需要一个JSON响应,因此接收它的相应PHP代码,将其保存到“upload”子目录中,并返回JSON响应可能如下所示:
<?php
header("Content-Type: application/json");
$allowedExts = array("zip", "gz");
$extension = end(explode(".", $_FILES["file"]["name"]));
if (in_array($extension, $allowedExts))
{
if ($_FILES["file"]["error"] > 0)
{
echo json_encode(array("success" => false, "error" => $_FILES["file"]["error"]));
}
else
{
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo json_encode(array("success" => false, "error" => $_FILES["file"]["name"] . " already exists"));
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
echo json_encode(array("success" => true));
}
}
}
else
{
echo json_encode(array("success" => false, "error" => "Invalid file type"));
}
?>
虽然我真的鼓励你使用AFNetworking,但如果你想构建自己的请求,你可以这样做:
[self uploadFileAtPath:zipFile forField:@"file" URL:[NSURL URLWithString:urlString] parameters:nil completion:^(BOOL success, NSString *errorMessage) {
NSLog(@"success = %d; errorMessage = %@", success, errorMessage);
}];
其中,uploadFileAtPath
和一些支持方法的定义如下:
- (void)uploadFileAtPath:(NSString *)path
forField:(NSString *)fieldName
URL:(NSURL*)url
parameters:(NSDictionary *)parameters
completion:(void (^)(BOOL success, NSString *errorMessage))completion
{
NSString *filename = [path lastPathComponent];
NSData *data = [NSData dataWithContentsOfFile:path];
NSMutableData *httpBody = [NSMutableData data];
NSString *boundary = [self generateBoundaryString];
NSString *mimetype = [self mimeTypeForPath:path];
// 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 (data) {
[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:data];
[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)
{
if (completion)
completion(FALSE, [NSString stringWithFormat:@"%s: sendAsynchronousRequest error: %@", __FUNCTION__, connectionError]);
return;
}
NSError *error = nil;
NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!responseObject)
{
if (completion)
completion(FALSE, [NSString stringWithFormat:@"%s: JSONObjectWithData error=%@", __FUNCTION__, error]);
return;
}
BOOL success = [responseObject[@"success"] boolValue];
NSString *errorMessage = responseObject[@"error"];
if (completion)
completion(success, errorMessage);
}];
}
- (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];
}
- (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;
}
答案 1 :(得分:1)
虽然我不推荐它(我希望看到格式正确的multipart/form-data
或application/JSON
请求),但您可以像这样创建您的请求:
NSData *zipData = [NSData dataWithContentsOfFile:zipFile]; // note, autorelease object
NSString *postLength = [NSString stringWithFormat:@"%d", [zipData length]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/zip" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:zipData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSString *result = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSInteger statusCode = -1;
if ([response isKindOfClass:[NSHTTPURLResponse class]])
statusCode = [(NSHTTPURLResponse *)response statusCode];
NSLog(@"Response Code: %d", statusCode);
if (statusCode >= 200 && statusCode < 300)
{
NSLog(@"Response: %@", result);
}
}];
然后您可以使用PHP代码读取此二进制数据并将其保存到文件中:
<?php
$handle = fopen("php://input", "rb");
$http_raw_post_data = '';
while (!feof($handle)) {
$http_raw_post_data .= fread($handle, 8192);
}
fclose($handle);
$handle = fopen('upload/myzip.zip', 'wb');
if ($handle == false) {
echo 'unable to open file';
exit (0);
}
$bytes = fwrite($handle, $http_raw_post_data);
if ($bytes == false)
echo 'write failed';
else
echo 'write succeeded';
fclose($handle);
?>