【问题标题】:File Upload to HTTP server in iphone programmingiphone编程中的文件上传到HTTP服务器
【发布时间】:2010-10-30 12:39:28
【问题描述】:

任何人都可以提供一些链接或示例以使用将文件上传到 HTTP 服务器 iphone API。

【问题讨论】:

  • 鉴于您无权访问文件系统...您将上传哪些文件?
  • @mmc 文件可能是您自己创建的?您确实可以访问沙箱中的文件系统。

标签: iphone http file-upload


【解决方案1】:

下面的代码使用 HTTP POST 将 NSData 发布到网络服务器。您还需要对 PHP 有一些了解。

NSString *urlString = @"http://yourserver.com/upload.php";
NSString *filename = @"filename";
request= [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];
NSString *boundary = @"---------------------------14737809831466499882746641449";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
[request addValue:contentType forHTTPHeaderField: @"Content-Type"];
NSMutableData *postbody = [NSMutableData data];
[postbody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"%@.jpg\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[NSData dataWithData:YOUR_NSDATA_HERE]];
[postbody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postbody];

NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSLog(@"%@", returnString);

【讨论】:

  • Brandon,感谢您在上述代码中的回复,我有一些问题,1)我们在哪里传递上传文件路径 2)我需要在这里传递 YOUR_NSDATA_HERE 实际上我的文件名为 test. txt 在这个路径 /Users/abc/Desktop/test.txt 你能告诉我我应该在哪里使用上面的代码传递这个信息,我执行上面的代码它给出了 NSInvalidArgumentException。请帮忙..--BP
  • 您需要将文本文件转换为 NSData。 NSData *data = [[NSData alloc] initWithContentsOfFile:path]; “路径”显然是您的文本文件的路径,例如 NSString *path = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"image.jpg"];
  • 我自己尝试过,但我不断从我的网络服务器收到关于发布消息格式的错误(System.InvalidOperationException:请求格式无效:multipart/form-data;边界=- --------------------------14737809831466499882746641449)。有人会出错吗?
  • 这看起来不错。我没有看到任何PHP。我认为您的意思是 HTTP。
  • @Marc 14737809831466499882746641449 是一个随机边界。你可以使用任何东西,但每个人总是使用14737809831466499882746641449。我完全不知道为什么,也许它被用于苹果的一些示例代码中。有人有什么想法吗?
【解决方案2】:

ASIHTTPRequest 是一个很好的网络 API 包装器,可以很容易地上传文件。这是他们的示例(但您也可以在 iPhone 上执行此操作 - 我们将图像保存到“磁盘”并稍后上传。

ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request setPostValue:@"Ben" forKey:@"first_name"];
[request setPostValue:@"Copsey" forKey:@"last_name"];
[request setFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photo"];

【讨论】:

  • 谢谢,这正是我想要的!我很惊讶,很难找到这样的东西。
  • ASI 很棒,我们也使用它。不要忘记启动请求(例如:[request startSynchronous]) 来源:allseeing-i.com/ASIHTTPRequest/How-to-use#streaming
  • 很遗憾,ASI 似乎在 IOS5 中不起作用,不再受支持。
  • 是的,这是正确的 - 遗憾的是,不再支持 ASIHTTPRequest。
  • @RussC 即使不支持它,它仍然可以工作——我让它在 iOS6 上工作,但不得不关闭文件的 ARC——然后我找到了 AFNetworking。
【解决方案3】:

我使用 ASIHTTPRequest 很像 Jane Sales answer,但它不再处于开发阶段,作者建议使用其他库,如 AFNetworking。

Honestly, I think now is the time to start looking elsewhere.

AFNetworking 效果很好,让您可以大量使用积木(这让您松了一口气)。

这是他们在github 上的文档页面上的图片上传示例:

NSURL *url = [NSURL URLWithString:@"http://api-base-url.com"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"avatar.jpg"], 0.5);
NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:@"POST" path:@"/upload" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
    [formData appendPartWithFileData:imageData name:@"avatar" fileName:@"avatar.jpg" mimeType:@"image/jpeg"];
}];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
    NSLog(@"Sent %lld of %lld bytes", totalBytesWritten, totalBytesExpectedToWrite);
}];
[httpClient enqueueHTTPRequestOperation:operation];

【讨论】:

  • 如果我们已经在 AFHTTPClient 基本 url 中包含了路径,我们需要设置什么"path"
【解决方案4】:

这是一个很棒的包装器,但是当发布到 asp.net 网页时,需要设置两个额外的发布值:

    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
    //ADD THESE, BECAUSE ASP.NET is Expecting them for validation
    //Even if they are empty you will be able to post the file
    [request setPostValue:@"" forKey:@"__VIEWSTATE"];
    [request setPostValue:@"" forKey:@"__EVENTVALIDATION"]; 
    ///

    [request setFile:FIleName forKey:@"fileupload_control_Name"];
    [request startSynchronous];

【讨论】:

    【解决方案5】:

    试试这个..很容易理解和实现...

    您可以直接在这里下载示例代码https://github.com/Tech-Dev-Mobile/Json-Sample

    - (void)simpleJsonParsingPostMetod
    {
    
    #warning set webservice url and parse POST method in JSON
        //-- Temp Initialized variables
        NSString *first_name;
        NSString *image_name;
        NSData *imageData;
    
        //-- Convert string into URL
        NSString *urlString = [NSString stringWithFormat:@"demo.com/your_server_db_name/service/link"];
        NSMutableURLRequest *request =[[NSMutableURLRequest alloc] init];
        [request setURL:[NSURL URLWithString:urlString]];
        [request setHTTPMethod:@"POST"];
    
        NSString *boundary = @"14737809831466499882746641449";
        NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
        [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
    
        //-- Append data into posr url using following method
        NSMutableData *body = [NSMutableData data];
    
    
        //-- For Sending text
    
            //-- "firstname" is keyword form service
            //-- "first_name" is the text which we have to send
        [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",@"firstname"] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"%@",first_name] dataUsingEncoding:NSUTF8StringEncoding]];
    
    
        //-- For sending image into service if needed (send image as imagedata)
    
            //-- "image_name" is file name of the image (we can set custom name)
        [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition:form-data; name=\"file\"; filename=\"%@\"\r\n",image_name] 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]];
    
    
        //-- Sending data into server through URL
        [request setHTTPBody:body];
    
        //-- Getting response form server
        NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    
        //-- JSON Parsing with response data
        NSDictionary *result = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil];
        NSLog(@"Result = %@",result);
    }
    

    【讨论】:

      【解决方案6】:

      这不是替代解决方案;而是对布兰登流行答案的建议(好像我没有足够的代表来评论该答案)。如果您要上传大文件;由于必须将文件读入内存才能将其发布到服务器,您可能会遇到 mmap malloc 异常。

      您可以通过替换来调整 Brandon 的代码:

      [request setHTTPBody:postbody];
      

      与:

      NSInputStream *stream = [[NSInputStream alloc] initWithData:postbody];
      [request setHTTPBodyStream:stream];
      

      【讨论】:

        【解决方案7】:

        我想我会在这个答案中添加一些服务器端 php 代码,以供阅读这篇文章并正在努力弄清楚如何在服务器端接收文件并将文件保存到文件系统的初学者。

        我意识到这个答案并没有直接回答 OP 的问题,但是由于 Brandon 的答案对于 iOS 设备端的上传来说已经足够了,而且他提到了一些 php 的知识是必要的,我想我会用这个答案。

        这是我整理的一个类以及一些示例使用代码。请注意,文件存储在基于用户上传文件的目录中。这可能适用于您的使用,也可能不适用,但我想我会保留它以防万一。

        <?php
        
        
        class upload
        {
            protected $user;
        
            protected $isImage;
            protected $isMovie;
        
            protected $file;
            protected $uploadFilename;
            protected $uploadDirectory;
            protected $fileSize;
            protected $fileTmpName;
            protected $fileType;
            protected $fileExtension;
        
            protected $saveFilePath;
        
            protected $allowedExtensions;
        
        function __construct($file, $userPointer)
        {
            // set the file we're uploading
            $this->file = $file;
        
            // if this is tied to a user, link the user account here
            $this->user = $userPointer;
        
            // set default bool values to false since we don't know what file type is being uploaded yet
            $this->isImage   = FALSE;
            $this->isMovie   = FALSE;
        
            // setup file properties
            if (isset($this->file) && !empty($this->file))
            {   
                $this->uploadFilename   = $this->file['file']['name'];
                $this->fileSize         = $this->file['file']['size'];
                $this->fileTmpName      = $this->file['file']['tmp_name'];
                $this->fileType         = $this->file['file']['type'];
            }
            else
            {
                throw new Exception('Received empty data. No file found to upload.');
            }
        
            // get the file extension of the file we're trying to upload
            $tmp = explode('.', $this->uploadFilename);
            $this->fileExtension        = strtolower(end($tmp));
        
        }
        
        
        
        public function image($postParams)
        {
            // set default error alert (or whatever you want to return if error)
            $retVal = array('alert' => '115');
        
            // set our bool
            $this->isImage = TRUE;
        
            // set our type limits
            $this->allowedExtensions    = array("png");
        
            // setup destination directory path (without filename yet)
            $this->uploadDirectory      = DIR_IMG_UPLOADS.$this->user->uid."/photos/";
        
            // if user is not subscribed they are allowed only one image, clear their folder here
            if ($this->user->isSubscribed() == FALSE)
            {
                $this->clearFolder($this->uploadDirectory);
            }
        
            // try to upload the file
            $success = $this->startUpload();
        
            if ($success === TRUE)
            {
                // return the image name (NOTE: this wipes the error alert set above)
                $retVal = array(
                                'imageName' =>  $this->uploadFilename,
                                );
            }
        
            return $retVal;
        }
        
        
        
        public function movie($data)
        {
            // update php settings to handle larger uploads
            set_time_limit(300);
        
            // you may need to increase allowed filesize as well if your server is not set with a high enough limit
        
            // set default return value (error code for upload failed)
            $retVal = array('alert' => '92');
        
            // set our bool
            $this->isMovie = TRUE;
        
            // set our allowed movie types
            $this->allowedExtensions = array("mov", "mp4", "mpv", "3gp");
        
            // setup destination path
            $this->uploadDirectory = DIR_IMG_UPLOADS.$this->user->uid."/movies/";
        
            // only upload the movie if the user is a subscriber
            if ($this->user->isSubscribed())
            {
                // try to upload the file
                $success = $this->startUpload();
        
                if ($success === TRUE)
                {
                    // file uploaded so set the new retval
                    $retVal = array('movieName' => $this->uploadFilename);
                }
            }
            else
            {
                // return an error code so user knows this is a limited access feature
                $retVal = array('alert' => '13');
            }
        
            return $retVal;
        }
        
        
        
        
        //-------------------------------------------------------------------------------
        //                          Upload Process Methods
        //-------------------------------------------------------------------------------
        
        private function startUpload()
        {
            // see if there are any errors
            $this->checkForUploadErrors();
        
            // validate the type received is correct
            $this->checkFileExtension();
        
            // check the filesize
            $this->checkFileSize();
        
            // create the directory for the user if it does not exist
            $this->createUserDirectoryIfNotExists();
        
            // generate a local file name
            $this->createLocalFileName();
        
            // verify that the file is an uploaded file
            $this->verifyIsUploadedFile();
        
            // save the image to the appropriate folder
            $success = $this->saveFileToDisk();
        
            // return TRUE/FALSE
            return $success;
        }
        
        private function checkForUploadErrors()
        {
            if ($this->file['file']['error'] != 0)
            {
                throw new Exception($this->file['file']['error']);
            }
        }
        
        private function checkFileExtension()
        {
            if ($this->isImage)
            {
                // check if we are in fact uploading a png image, if not return error
                if (!(in_array($this->fileExtension, $this->allowedExtensions)) || $this->fileType != 'image/png' || exif_imagetype($this->fileTmpName) != IMAGETYPE_PNG)
                {
                    throw new Exception('Unsupported image type. The image must be of type png.');
                }
            }
            else if ($this->isMovie)
            {
                // check if we are in fact uploading an accepted movie type
                if (!(in_array($this->fileExtension, $this->allowedExtensions)) || $this->fileType != 'video/mov')
                {
                    throw new Exception('Unsupported movie type. Accepted movie types are .mov, .mp4, .mpv, or .3gp');
                }
            }   
        }
        
        private function checkFileSize()
        {
            if ($this->isImage)
            {
                if($this->fileSize > TenMB)
                {
                    throw new Exception('The image filesize must be under 10MB.');
                }
            }
            else if ($this->isMovie)
            {
                if($this->fileSize > TwentyFiveMB) 
                {
                    throw new Exception('The movie filesize must be under 25MB.');
                }
            }
        }
        
        private function createUserDirectoryIfNotExists()
        {
            if (!file_exists($this->uploadDirectory)) 
            {
                mkdir($this->uploadDirectory, 0755, true);
            }
            else
            {
                if ($this->isMovie)
                {
                    // clear any prior uploads from the directory (only one movie file per user)
                    $this->clearFolder($this->uploadDirectory);
                }
            }
        }
        
        private function createLocalFileName()
        {
            $now = time();
        
            // try to create a unique filename for this users file
            while(file_exists($this->uploadFilename = $now.'-'.$this->uid.'.'.$this->fileExtension))
            {
                $now++;
            }
        
            // create our full file save path
            $this->saveFilePath = $this->uploadDirectory.$this->uploadFilename;
        }
        
        private function clearFolder($path)
        {
            if(is_file($path))
            {
                // if there's already a file with this name clear it first
                return @unlink($path);
            }
            elseif(is_dir($path))
            {
                // if it's a directory, clear it's contents
                $scan = glob(rtrim($path,'/').'/*');
                foreach($scan as $index=>$npath)
                {
                    $this->clearFolder($npath);
                    @rmdir($npath);
                }
            }
        }
        
        private function verifyIsUploadedFile()
        {
            if (! is_uploaded_file($this->file['file']['tmp_name']))
            {
                throw new Exception('The file failed to upload.');
            }
        }
        
        
        private function saveFileToDisk()
        {
            if (move_uploaded_file($this->file['file']['tmp_name'], $this->saveFilePath))
            {
                return TRUE;     
            }
        
            throw new Exception('File failed to upload. Please retry.');
        }
        
        }
        
        
        ?>
        

        这里有一些示例代码演示了如何使用上传类...

        // get a reference to your user object if applicable
        $myUser = $this->someMethodThatFetchesUserWithId($myUserId);
        
        // get reference to file to upload
        $myFile = isset($_FILES) ? $_FILES : NULL;
        
        // use try catch to return an error for any exceptions thrown in the upload script
        try 
        {
            // create and setup upload class
            $upload = new upload($myFile, $myUser);
        
            // trigger file upload
            $data   = $upload->image();     // if uploading an image
            $data  = $upload->movie();      // if uploading movie
        
            // return any status messages as json string
            echo json_encode($data);
        } 
        catch (Exception $exception) 
        {
            $retData = array(
                    'status'    => 'FALSE',
                    'payload'   => array(
                                    'errorMsg' => $exception->getMessage()
                                    ),
                        );
        
            echo json_encode($retData);
        }
        

        【讨论】:

          【解决方案8】:

          我已经为 Mobile-AppSales 应用程序制作了一种轻量级备份方法,网址为github

          我在这里写了http://memention.com/blog/2009/11/22/Lightweight-backup.html

          ReportManager.m中寻找- (void)startUpload方法

          【讨论】:

            【解决方案9】:

            @Brandon 答案的更新,概括为一种方法

            - (NSString*) postToUrl:(NSString*)urlString data:(NSData*)dataToSend withFilename:(NSString*)filename
            {
                NSMutableURLRequest *request= [[NSMutableURLRequest alloc] init];
                [request setURL:[NSURL URLWithString:urlString]];
                [request setHTTPMethod:@"POST"];
                NSString *boundary = @"---------------------------14737809831466499882746641449";
                NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
                [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
                NSMutableData *postbody = [NSMutableData data];
                [postbody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
                [postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
                [postbody appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
                [postbody appendData:[NSData dataWithData:dataToSend]];
                [postbody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
                [request setHTTPBody:postbody];
            
                NSError* error;
                NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
                if (returnData) {
                    return [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
                }
                else {
                    return nil;
                }
            }
            

            像这样调用,从字符串发送数据:

            [self postToUrl:@"<#Your url string#>"
                       data:[@"<#Your string to send#>" dataUsingEncoding:NSUTF8StringEncoding]
               withFilename:@"<#Filename to post with#>"];
            

            【讨论】:

              猜你喜欢
              • 2010-11-18
              • 1970-01-01
              • 2014-02-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-04-12
              • 1970-01-01
              相关资源
              最近更新 更多