Uploading a large video from iphone to web server - php

I'm trying to upload a large video from iphone to a web server that has php script.
I'm using NSInputStream to get file video chunks and I'm creating a request(POST) on each traversal of the
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
method, with the read data passed as parameter.
Here is the code I'm using to get chunks of data
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch(eventCode)
{
case NSStreamEventHasBytesAvailable:
{
NSMutableData *dataSlice;
uint8_t buf[1048576];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1048576];
if(len)
{
dataSlice = [NSMutableData dataWithBytes:(const void *)buf length:len];
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:folderNameForUpload, kFolderName,
#"abcd.MOV", kFileName,
#"MOV", kFileType,
nil];
MKNetworkOperation *op = [self.networkEngine operationWithPath:#"upload.php" params:params httpMethod:#"POST"];
[op addData:dataSlice forKey: #"file"
mimeType: #"image/mov"
fileName: #"abcd"];
[op onCompletion:^(MKNetworkOperation *completedOperation) {
} onError:^(NSError *error) {
}];
[[WebRequest sharedInstance].networkEngine enqueueOperation: op];
}
else
{
NSLog(#"NO MORE BUFFER!");
}
break;
}
case NSStreamEventEndEncountered:
{
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream release];
stream = nil;
break;
}
}
}
It is sending the data to the server, and I'm able to write the chunks into a file. But, the problem is that, if there are more than one chunk, the file will become corrupted and I'm not able to open the video file.
I checked the file size on both server and client, and both are exactly same.
Below is the php script, I'm using to merge video file chunks.
$tmp_file = $_FILES['file']['tmp_name'];
$write_handle = fopen($fileURL, "ab+");
$read_handle = fopen($tmp_file, "rb");
$contents = fread($read_handle, filesize($tmp_file));
fwrite($write_handle, $contents);
fclose($write_handle);
fclose($read_handle);
What Am I doing wrong here?, Please help!
I'm stuck over this problem!!
Thanks in Advance,
Suraj

I got the problem myself guys. Actually, I was sending different chunks of video at the same time. And the problem was arising because the later chunks of video reached server before the first chunk of video.
I solved the problem by sending second chunk of video only after the first chunk is reached web server and the response is got at the client side.

Related

Download files from the download server with the help of php and mvc

I have a download server for files.
And I want my users to get the files from the download server.
My download server is Linux.
I want when the user clicks on the download button.
Get the file directly from the download server.
I do not want to use the stream to download ...
I want to connect to the download server via the link and then download it using PHP
My site is with mvc
Thank you, step by step to help me
thank you
Stream stream = null;
//This controls how many bytes to read at a time and send to the client
int bytesToRead = 10000;
// Buffer to read bytes in chunk size specified above
byte[] buffer = new Byte[bytesToRead];
// The number of bytes read
try
{
//Create a WebRequest to get the file
HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create(Global.UrlVideoPrice + IdCourse + "//" + IdTopic+".rar");
//Create a response for this request
HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
//Get the Stream returned from the response
stream = fileResp.GetResponseStream();
// prepare the response to the client. resp is the client Response
var resp = System.Web.HttpContext.Current.Response;
//Indicate the type of data being sent
resp.ContentType = "application/octet-stream";
//Name the file
resp.AddHeader("Content-Disposition", "attachment; filename=\"" + Topic.fldName + ".rar\"");
resp.AddHeader("Content-Length", fileResp.ContentLength.ToString());
int length;
do
{
// Verify that the client is connected.
if (resp.IsClientConnected)
{
// Read data into the buffer.
length = stream.Read(buffer, 0, bytesToRead);
// and write it out to the response's output stream
resp.OutputStream.Write(buffer, 0, length);
// Flush the data
resp.Flush();
//Clear the buffer
buffer = new Byte[bytesToRead];
}
else
{
// cancel the download if client has disconnected
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
}
}
This is my download code.
Now I want the user to get the files directly from the download server.
Do not use site traffic to download the file.
And use server download traffic

Make requests and handle responses for resumable upload: Google Drive api [php]

I'm using the API Client Library for PHP (Beta) to work with google drive api, So far I can authorize and and upload a file in chuncks.
According to the documentation, these three steps should be taken to upload a file:
Start a resumable session.
Save the resumable session URI.
Upload the file.
Which I think the Client Library handles.
Again, according to the documentation, if I want to show the progress or resume an interrupted upload, or to handle errors I need to capture the response and also be able to send requests like this:
> PUT {session_uri} HTTP/1.1 Content-Length: 0 Content-Range: bytes
> */2000000
But I have no idea how should I make such request and where can I get the response from, the php code I'm using to upload,like any other php code, only returns values when it is done executing, which is when the upload is done.
here is the function I'm using to upload files (Resumable):
function uploadFile($service,$client,$filetoUpload,$parentId){
$file = new Google_Service_Drive_DriveFile();
$file->title = $filetoUpload['name'];
$chunkSizeBytes = 1 * 1024 * 1024;
// Set the parent folder.
if ($parentId != null) {
$parent = new Google_Service_Drive_ParentReference();
$parent->setId($parentId);
$file->setParents(array($parent));
}
// Call the API with the media upload, defer so it doesn't immediately return.
$client->setDefer(true);
$request = $service->files->insert($file);
// Create a media file upload to represent our upload process.
$media = new Google_Http_MediaFileUpload(
$client,
$request,
$filetoUpload['type'],
null,
true,
$chunkSizeBytes
);
$media->setFileSize(filesize($filetoUpload['tmp_name']));
// Upload the various chunks. $status will be false until the process is
// complete.
$status = false;
$handle = fopen($filetoUpload['tmp_name'], "rb");
while (!$status && !feof($handle)) {
set_time_limit(120);
$chunk = fread($handle, $chunkSizeBytes);
$status = $media->nextChunk($chunk);
}
// The final value of $status will be the data from the API for the object
// that has been uploaded.
$result = false;
if($status != false) {
$result = $status;
set_time_limit(30);
echo "<pre>";
print_r($result);
}
fclose($handle);
// Reset to the client to execute requests immediately in the future.
$client->setDefer(false);
}
Should i make a separate php file to handle these requests?
if so, How should tell that which file's status I'm requesting for?
Thanks.
Apperantly, the BETA Client API simply doesn't support resuming Uploads.
Please see this issue on Github, which asks for fixing this. Of course it should be easy to modify the class (see below) and create a Pull-request to enable support for resuming existing uploads when the session-URL is supplied.
However, there's an easy way to get the progress after an chunk has been uploaded.
The Google_Http_MediaFileUpload-object ($media in your example) has a public method called 'getProgress' which can be called anytime.
(Please have a look at the source code of the API-client-library).
To get the upload status, I'd add a parameter to modify the progress precision by adjusting the chunk size. Since the more chunks are used, the more protocol overhead is generated, setting the precision as low as possible should be avoided.
Therefore, you could modify your source code as below to output the progress after each chunk:
function uploadFile($service,$client,$filetoUpload,$parentId,$progressPrecision = 1){
$file = new Google_Service_Drive_DriveFile();
$file->title = $filetoUpload['name'];
$filesize = filesize($filetoUpload['tmp_name']);
//minimum chunk size needs to be 256K
$chunkSizeBytes = min( $filesize / 100 * $progressPrecision, 262144);
// Set the parent folder.
if ($parentId != null) {
$parent = new Google_Service_Drive_ParentReference();
$parent->setId($parentId);
$file->setParents(array($parent));
}
// Call the API with the media upload, defer so it doesn't immediately return.
$client->setDefer(true);
$request = $service->files->insert($file);
// Create a media file upload to represent our upload process.
$media = new Google_Http_MediaFileUpload(
$client,
$request,
$filetoUpload['type'],
null,
true,
$chunkSizeBytes
);
$media->setFileSize($filesize);
…
while (!$status && !feof($handle)) {
set_time_limit(120);
$chunk = fread($handle, $chunkSizeBytes);
$status = $media->nextChunk($chunk);
if(!$status){ //nextChunk() returns 'false' whenever the upload is still in progress
echo 'sucessfully uploaded file up to byte ' . $media->getProgress() .
' which is ' . ( $media->getProgress() / $chunkSizeBytes ) . '% of the whole file';
}
}
Hope this helps. I'll see if I can find some time to add resume-support to the client Library.
EDIT: according to this doc, the chunks need to be at least 256KB big. Changed in code.
EDIT2: I just added a Pull request To add the Resume-Feature. If it gets rejected you could still decide whether it would be ok for you to modify/extend the client. If it gets accepted, just use store the return value of $media->getResumeUri() in a database, and later call $media->resume($previously_stored_return_value) after instantiation to resume the process.
On the first instance, make an upload call and get the resumeUri:
$chunk = fread($handle, 1*1024*1024);
$result = $media->nextChunk($chunk);
$resumeUri = $media->getResumeUri();
$offset = ftell($handle);
On the second instance use the same resumeUri to resume the upload from where we left out by calling resume() function before nextChunk() function:
if ($resumeUri) {
$media->resume($resumeUri);
}
fseek($handle, $offset);
$chunk = fread($handle, 1*1024*1024);
$result = $media->nextChunk($chunk);
Repeat the process until the $result variable has truthy value.

Sending an NSURLRequest to phpMyAdmin results in the NSData being the php source code

I have had quite the night trying to solve problems after "Upgrading" to OS X Yosemite 10.6.6. After re-installing MySQL / phpMyAdmin / Apache / php5 I am still having problems with code that worked before the upgrade. The following function sends a URL request to a locally hosted php file to obtain data from a MySQL data base in a JSON parable format:
-(NSArray*) GetJSONArrayForURL:(NSString*)url
{
// Download the json file
NSURL *jsonFileUrl = [NSURL URLWithString:url];
// Create the request
//NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
NSURLResponse* response = nil;
NSData *rawdata = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSMutableData *downloaded = [[NSMutableData alloc] init];
[downloaded appendData:rawdata];
// Parse the JSON that came in
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:downloaded options:NSJSONReadingAllowFragments error:&error];
return jsonArray;
}
However, the raw data returned is the source code of the PHP file it is requesting:
<?php
$serverName = "localhost";
$databaseName = "GUESTLISTER";
$userName = $_GET['username'];
$password = $_GET['password'];
$POST = "POST";
$GET = "GET";
// Create connection
$con=mysqli_connect($serverName,$userName,$password,$databaseName);
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
// This SQL statement selects ALL from the table 'Locations'
//$sql = "SELECT * FROM users";
$sql = $_GET['query'];
$action = $_GET['action'];
// Check if there are results
if ($result = mysqli_query($con, $sql))
{
$id = mysqli_insert_id($con);
if($action == $GET)
{
// If so, then create a results array and a temporary one
// to hold the data
$resultArray = array();
$tempArray = array();
// Loop through each row in the result set
while($row = $result->fetch_object())
{
// Add each row into our results array
$tempArray = $row;
array_push($resultArray, $tempArray);
}
// Finally, encode the array to JSON and output the results
echo json_encode($resultArray);
}
else if ($action == $POST)
{
echo $id;
}
}
// Close connections
mysqli_close($con);
?>
The request which is:
http://localhost/webservice.php?&username=admin&password=guestlister123&query=SELECT%20*%20FROM%20users&action=GET
Runs fine when pinged from a web browser, but for some bizarre reason the source code is returned as data when requested from Xcode.
Please advise,
Ryan
Usually when the same source code is returned instead of its output, it points to the issue that Php is not getting parsed as Php. That means there is an issue with the setup for your webserver - Apache since its unable to process Php. There can be many different reasons for this, a few of them can be
Apache is off and may need to be turned on, which since outside the xcode it works then that may not be the case
Apache configuration for Php is not set up correctly
The website is not in the folder where Apache expects it to be. htdocs is usually the default where Apache looks for php scripts depending on the php.ini configuration. A quickest way is to run the phpinfo(); in a php file between the starting and ending php tags to determine if all is well with your setup.
phpinfo();
If its set up correctly you would see an output page with all the information about your php and apache setup else it will just give you back the phpinfo() line as output. Finally it could just be that Xcode is not working properly with your Apache setup thus it can be beneficial to directly run scripts through the browser instead of within Xcode which I have never tried.

AFNetworking Upload Using NSMutableURLRequest?

I'm trying to learn AFNetworking, and I've taken a sample from their Github. I don't know what parameters to set in dataToPostusing the the php I have. I'm new to Objective-C and php. Can someone take a look at my snippet and my php to see what I'm missing. It's hard to find "upload" tutorials for AFNetworking, but there are TONS of JSON tutorials out there.
I want to use a NSMutableURLRequest because eventually I would like to upload from an array or UITableview; here is mt code so far:
PHP:
<?php
header("Content-Type: application/json");
$uploaddir = './'; //Uploading to same directory as PHP file
$file = basename($_FILES['userfile']['name']);
$uploadFile = $file;
$randomNumber = rand(0, 99999);
$newName = $uploadDir . $randomNumber . $uploadFile;
if (!is_uploaded_file($_FILES['userfile']['tmp_name'])) {
$result = array("success" => false);
echo json_encode($result);
exit();
}
if ($_FILES['userfile']['size']> 300000) {
$result = array("success" => false, "message" =>"the uploaded file is too big");
echo json_encode($result);
exit();
}
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $newName)) {
$postsize = ini_get('post_max_size'); //Not necessary, I was using these
$canupload = ini_get('file_uploads'); //server variables to see what was
$tempdir = ini_get('upload_tmp_dir'); //going wrong.
$maxsize = ini_get('upload_max_filesize');
//echo "http://localhost:8888/upload/{$file}" . "\r\n" . $_FILES['userfile']['size'] . "\r\n" . $_FILES['userfile']['type'] ;
$result = array("success" => true,
"code" => 0,
"message" => "success",
"postsize" => $postsize,
"canupload" => $canupload,
"tempdir" => $tempdir,
"maxsize" => $maxsize);
echo json_encode($result);
}
?>
Xcode:
// 1. Create AFHTTPRequestSerializer which will create your request.
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
// 2. Create an NSMutableURLRequest.
NSMutableURLRequest *request =
[serializer multipartFormRequestWithMethod:#"POST" URLString:#"http://my.com/upload/upload.php"
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData
name:#"userfile"
fileName:#"myimage.jpg"
mimeType:#"image/jpeg"];
}];
// 3. Create and use AFHTTPRequestOperationManager to create an AFHTTPRequestOperation from the NSMutableURLRequest that we just created.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperation *operation =
[manager HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure %#", error.description);
}];
// 4. Set the progress block of the operation.
[operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten,
NSInteger totalBytesWritten,
NSInteger totalBytesExpectedToWrite) {
NSLog(#"Wrote %ld/%ld", (long)totalBytesWritten, (long)totalBytesExpectedToWrite);
}];
// 5. Begin!
[operation start];
ERROR (resolved):
2014-03-31 15:37:46.921 TestingUpload[7190:60b] Wrote 32768/59063
2014-03-31 15:37:46.922 TestingUpload[7190:60b] Wrote 59063/59063
2014-03-31 15:37:46.923 TestingUpload[7190:60b] Wrote 32768/59063
2014-03-31 15:37:46.923 TestingUpload[7190:60b] Wrote 59063/59063
2014-03-31 15:37:46.925 TestingUpload[7190:60b] Success {
canupload = 1;
code = 0;
maxsize = 32M;
message = success;
postsize = 32M;
success = 1;
tempdir = "/Applications/MAMP/tmp/php";
}
2014-03-31 15:37:46.927 TestingUpload[7190:60b] Success {
canupload = 1;
code = 0;
maxsize = 32M;
message = success;
postsize = 32M;
success = 1;
tempdir = "/Applications/MAMP/tmp/php";
}
Thanks for any help and explanation. Thank you!
Your PHP is looking for the field name userfile, but your Objective-C is using attachment. You must use the same field name on both platforms. I also assume the "<$php" was just a typo and that you intended "<?php".
A couple of other improvements you might want to consider:
I would suggest that you might want to change your PHP to return JSON rather than just writing text strings. It will be easier for your Objective-C code to parse the responses and differentiate between various errors and success.
For example, your if successful, your PHP might do the following:
$result = array("success" => true, "code" => 0, "message" => "success");
Or if you wanted to log those additional values, as in your existing code sample, you could:
$result = array("success" => true,
"code" => 0,
"message" => "success",
"postsize" => $postsize,
"canupload" => $canupload,
"tempdir" => $tempdir,
"maxsize" => $maxsize);
If unsuccessful, you might do:
$result = array("success" => false, "code" => 1, "message" => "file not found");
or
$result = array("success" => false, "code" => 2, "message" => "file too large");
Regardless of which $result is chosen, when done, you should JSON encode it and echo it (rather than echoing the simple text string):
echo json_encode($result);
Clearly, use whatever codes and messages you want, but the idea is to return JSON, which can be easily parsed to determine if the upload request was successful, and if not, then why. Trying to parse simple text responses from the server will be inherently fragile.
Anyway, your Objective-C can then parse this response and just check the success or code values and handle these scenarios appropriately.
I would not suggest having the PHP save the uploads in the same folder as the PHP, itself. At the very least, I'd create a dedicated subdirectory for the uploads. I'd personally choose a directory completely outside the web server's directory structure.
On the basis of your updated code sample and reported warnings/errors, I have a few observations:
You are receiving the message about multipartFormRequestWithMethod being deprecated because you're using the rendition without the error parameter, but that's been replaced with another rendition with this additional parameter. See the declaration of this method in AFURLRequestSerialization.h for more information.
Your error about the text/html is a result of the fact that PHP is sending a response with a header that reports a Content-type of text/html. If your PHP script is not sending JSON back in your PHP, you have to change your your Objective-C code so it knows to expect an HTTP response (by default, it expects JSON back):
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
That tells the AFHTTPRequestOperationManager to accept any HTTP response back from the server.
Alternatively, if you change your PHP to return JSON (and you should, IMHO), you need to not only change the PHP code to echo the json_encode of the results, but also inform PHP to specify the appropriate Content-Type in the header. So before you echo any JSON in your PHP), add the following line to the PHP code:
header("Content-Type: application/json");
You said:
I thought the content type was defined in mimetype
The mimetype defines the Content-type for that part of the multipart request. But the whole request has its own Content-type header, too. The response also bears a Content-type setting in its header. This error, is telling you that the response bore a Content-type of text/html, and it expected application/json. (See my prior point regarding fixing that.)

Can't write image file on actual server

I'm working with android and try to create an app that able to upload several image to the server. I had tried to upload the image to my localhost using xampp, it works well. But when I try to upload to my enterprise server I can't find my file, in the other word. The file can't be written. I don't know what make it failed? This is my code
Upload tp XAMPP
Connection string private static final String url_photo = "http://192.168.7.110/blabla/base.php";
Path static final String path = "C:\\xampp\\htdocs\\psn_asset_oracle\\Images\\";
Upload to actual enterprise server
Connection String private static final String url_photo = "http://192.168.4.27/oracle/logam/am/data_images/android_image/base.php";
Path static final String path = "http://192.168.4.27/oracle/logam/am/data_images/android_image/";
My code to upload to server
params_p.add(new BasicNameValuePair("image_name_1",
image_name_1));
params_p.add(new BasicNameValuePair("image_name_2",
image_name_2));
params_p.add(new BasicNameValuePair("image_name_3",
image_name_3));
params_p.add(new BasicNameValuePair("image_name_4",
image_name_4));
json_photo = jsonParser.makeHttpRequest(url_photo, "POST", params_p);
ArrayList<NameValuePair> params_p = new ArrayList<NameValuePair>();
PHP code
if(isset($_POST["image_name_1"]) && isset($_POST["image_name_2"]) && isset($_POST["image_name_3"]) && isset($_POST["image_name_4"])
&& isset($_POST["image_1"]) && isset($_POST["image_2"]) && isset($_POST["image_3"]) && isset($_POST["image_4"]))
{
$image_name_1 = $_POST["image_name_1"];
$image_name_2 = $_POST["image_name_2"];
$image_name_3 = $_POST["image_name_3"];
$image_name_4 = $_POST["image_name_4"];
$image_1 = $_POST["image_1"];
$image_2 = $_POST["image_2"];
$image_3 = $_POST["image_3"];
$image_4 = $_POST["image_4"];
/*---------base64 decoding utf-8 string-----------*/
$binary_1=base64_decode($image_1);
$binary_2=base64_decode($image_2);
$binary_3=base64_decode($image_3);
$binary_4=base64_decode($image_4);
/*-----------set binary, utf-8 bytes----------*/
header('Content-Type: bitmap; charset=utf-8');
/*---------------open specified directory and put image on it------------------*/
$file_1 = fopen($image_name_1, 'wb');
$file_2 = fopen($image_name_2, 'wb');
$file_3 = fopen($image_name_3, 'wb');
$file_4 = fopen($image_name_4, 'wb');
/*---------------------assign image to file system-----------------------------*/
fwrite($file_1, $binary_1);
fclose($file_1);
fwrite($file_2, $binary_2);
fclose($file_2);
fwrite($file_3, $binary_3);
fclose($file_3);
fwrite($file_4, $binary_4);
fclose($file_4);
$response["message"] = "Success";
echo json_encode($response);
}
I've contact my DBA and asked to give me permission to write the file, and it still doesn't work. The error is json doesn't give "Success" as message that indicate the file failed to be written. I will appreciate any help. Thank you.
Does the file server allows write access permission? Sample of chmod, http://catcode.com/teachmod/
Is your enterprise server online? The IP address looks private to me, 192.168.4.27.
Dont use json use http post.
See below code
HttpClient client = new DefaultHttpClient();
String postURL = "your url";
HttpPost post = new HttpPost(postURL);
try {
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
ByteArrayBody bab = new ByteArrayBody(img, "image.jpg");
reqEntity.addPart("image", bab);
post.setEntity(reqEntity);
HttpResponse response = client.execute(post);
Here img is your image in ByteArray format
The problem solved after my DBA give me another file path.

Categories