How to start a download when file is processing by a software - php

I encode a file with a special watermark for be downlaoded by the user
I would like to be able to start the downlaod when ffmpeg encode the file.
I have a php page which one create the water mark , launch ffmpeg and start the download with X-sendifle
The download don't start, adding sleep(15) let's the download start just I receive only what is done
Actually I use Apache2 as the webserver with X-sendfile mod

Okay I finally find how to do
Using X-sendfile it's a wrong idea
Using mp4 it's a wrong idea because at the end of the encodage the software rewrite 4 bytes at the beginning of the file
So this is the code I use for be able to send a file like webm or flv files when ffmpeg encode the output
shell_exec('ffmpeg command');
sleep(2); //wait few second for the software start
$foutput ="where/is/your/output.file";
header('Content-Disposition: attachment; file.name.for.the.user"');
header("Keep-Alive:timeout=200, max=500");
//sending by chunk
set_time_limit(3600);
$file =fopen($foutput , 'r');
$files = fstat($file);
$filesize= $files['size'];
$last = 0;
echo fread($file , $filesize);
sleep(5); //wait a little for the software add new bytes
$last = $filesize;
$files = fstat($file);
$filesize= $files['size'];
$done =0;
while( $done < 2 ){
if ($filesize != $last){
fseek($file , $last);
$read = $filesize - $last ;
echo fread($file , $read);
$last =$filesize;
sleep(5);
$files = fstat($file);
$filesize= $files['size'];
}else{
fclose($file);
return 0;
};
};
I'm a noob for coding and got a problem with my "while" just the code work really good without any issue
Do not use filesize , this command don't like when a file change of size all time and return only 4096 in that case
The download will be slow , this is normal , you receive chunk by chunk what the software done like with ffmpeg the transfer is between 200 to 1200 kb/s

Related

How to read the first 10000 lines from file and write them in another? PHP

Hello i have this code:
file1 = file_get_contents("read.txt");
$path2 = "write.txt";
$file2 = file_get_contents($path2);
if ($file1 !== $file2){
file_put_contents($path2, $file1);
echo "working";
}
how can i get the first 10000 lines or more from the read.txt file and write them in write.txt ?
There are many ways you could do this reading the entire file, but it would be better to use streams and only read the data you need.
<?php
$source="file.txt";
$destination="file2.txt";
$requiredLines=10000;
//compare the modification times, if source is newer than destination - then we do our work
if(filemtime($source)>filemtime($destination)){
//work out maximum length of file, as one line may be the whole file.
$filesize = filesize($source);
//open file for reading - this doesnt actually read the file it allows us to "stream" it
$sourceHandle = fopen($source, "r");
//open file for writing
$destinationHandle = fopen($destination, "w");
$linecount=0;
//loop through file until we reach the end of the file (feof) or we reach the desired number of lines
while (!feof($sourceHandle) && $linecount++<$requiredLines) {
//read one line
$line = stream_get_line($sourceHandle, $filesize, "\n");
//write the line
fwrite($destinationHandle,$line);
}
//close both files
fclose($sourceHandle);
fclose($destinationHandle);
}
You can find more info on streams here: Understanding PHP Streams

Downloading or copying large files from server to server

I have used this code to copy a 45 mb zipfile from A server to B server.
<?php
set_time_limit(0);
$file = 'https://www.xxxxx.com/Products.zip';
$newfile = 'Products.zip';
if ( copy($file, $newfile) ) {
echo "Copy success!";
}else{
echo "Copy failed.";
}
?>
After copying 17 mb itis giving server error.
I have used some other codes to download or copy from server to server like
<?php
set_time_limit(0);
$url = 'https://www.mydomaind.com/Products.zip';
$path = 'Products.zip';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
curl_close($ch);
file_put_contents($path, $data);
echo 'done';
?>
Another one
<?php
set_time_limit(0);
$source =("https://www.mydomaind.com/Products.zip");
$destination = 'Produtcs.zip';
$data = file_get_contents($source);
$handle = fopen($destination, "w");
fwrite($handle, $data);
fclose($handle);
echo 'done';
?>
These last to code download or copy files like 5 mb easily.
But when itry to same job for 50 mb. Gives error.
Please helpme how i can do that.
Thanks
Your hitting php limit.
Look inside php.ini and up the limit
; Maximum allowed size for uploaded files.
upload_max_filesize = 40M
; Must be greater than or equal to upload_max_filesize
post_max_size = 40M
p.s. you should not use PHP for sending files between servers.
Better use SSH and SCP. PHP can lunch commands with exec() than you use shell to send file.
If you are hitting your limit, here is another SO answer on how to set it in .htaccess
Changing upload_max_filesize on PHP
Sorry to respond here mods, can't comment yet!
Already tried to split/cut the zip into 2/3 parts? Imho would that solve your prob without any errors from servver side.
Try using this code so that you do not use up the available RAM on your server.
function chunked_copy() {
# write with buffer, 1 meg at a time, adjustable.
$buffer_size = 1048576;
$ret = 0;
$fin = fopen("http://www.example.com/file.zip", "rb"); #source
$fout = fopen("file.zip", "w"); #destination
while(!feof($fin)) {
$ret += fwrite($fout, fread($fin, $buffer_size));
}
fclose($fin);
fclose($fout);
return $ret; # return number of bytes written
}

php decode base 64 very big file, not a string

i have a system that saves files to the server harddrive in base 64 encoded after stripping them from email files.
i would like to change the file to thier original format again, how can i do that in php?
this is how i tried to save the files but that does not seem to create a valid files:
$start = $part['starting-pos-body'];
$end = $part['ending-pos-body'];
$len = $end-$start;
$written = 0;
$write = 2028;
$body = '';
while ($start <= $end) {
fseek($this->stream, $start, SEEK_SET);
$my = fread($this->stream, $write);
fwrite($temp_fp, base64_decode($my));
$start += $write;
}
fclose($temp_fp);
#traylz makes the point clear for why it may fail when it shouldn't. However, base64_decode() may fail for large images even. I have worked with 6 to 7 MB files fine, I haven't gone over this size, so for me it should be as simple as:
$dir = dirname(__FILE__);
// get the base64 encoded file and decode it
$o_en = file_get_contents($dir . '/base64.txt');
$d = base64_decode($o_en);
// put decoded string into tmp file
file_put_contents($dir . '/base64_d', $d);
// get mime type (note: mime_content_type() is deprecated in favour
// for fileinfo functions)
$mime = str_replace('image/', '.', mime_content_type($dir . '/base64_d'));
rename($dir . '/base64_d', $dir . '/base64_d' . $mime);
If the following fails try adding chunk_split() function to decode operation:
$d = base64_decode(chunk_split($o_en));
So what am I sayaing...forget the loop unless there is a need for it...keep the orignal file extension if you don't trust php's mime detection. use chunk_split() on base64_decode() operation if working on large files.
NOTE: all theory so untested
EDIT: for large files that mostly likely will freeze file_get_contents(), read in what you need, output to file so little RAM is used:
$chunkSize = 1024;
$src = fopen('base64.txt', 'rb');
$dst = fopen('binary.mime', 'wb');
while (!feof($src)) {
fwrite($dst, base64_decode(fread($src, $chunkSize)));
}
Your problem is that you read 2028 chunks, checking start<=end AFTER you read chunk,so you read beyond end pointer, and you should check < insead of <= (to avoid reading 0 bytes)
Also you don't need to fseek on every iteration, because fread reads from current position. You can take fssek out of loop( before while).Why 2028 btw?
Try this out:
fseek($this->stream, $start, SEEK_SET);
while ($start < $end) {
$write = min($end-$start,2048);
$my = fread($this->stream, $write);
fwrite($temp_fp, base64_decode($my));
$start += $write;
}
fclose($temp_fp);
thank you all guys for the help
finally i ended up with:
shell_exec('/usr/bin/base64 -d '.$temp_file.' > '.$temp_file.'_s');

Trigger action when file download actually completes

Nowdays there are a lot of websites for files hosting (uploading websites) and it count for example point per complete download of certain file.
My question
I want to understand what is the idea they are using !
How does it only count on complete downloading of the file ?!
i mean if i canceled downloading of the file after it started , it won't count point!
how does it knew ! is there any php function that able to know if i canceled downloading certain exact file or not !
that question was all time in my mind and thinking about it but i can't understand how does it works or what is the idea behind it. ~ thanks
This can be done by using my other answer as base How can I give download access to files outside public_html directory? and replacing readfile( $filename )
with readfileWhileConnected( $filename ):
Read file until EOF or disconnect:
/** Read $filename until EOF or disconnect,
* if disconnect then error_log() count of bytes read already
*/
function readfileWhileConnected( $filename ) {
// Save and set ini values:
$user_abort = ignore_user_abort();
ignore_user_abort(false);
// Get file size and set bytes_sent to zero:
$fsize = filesize($filename);
$bytes_sent = 0;
// Open file:
$f = fopen($filename, 'r');
// Read file:
while($chunk = fread($f, 1024)) {
// Check if connection is still open:
if(!connection_aborted()) {
// Send $chunk to buffer (if any), then flush() buffers:
echo $chunk;
flush();
// Add $chunk length to $bytes_sent
$bytes_sent += strlen($chunk);
} else {
// Close file:
fclose($f);
error_log("Connection closed at $bytes_sent/$fsize");
exit();
}
// Close file:
fclose($f);
// Reset ini values:
ignore_user_abort($user_abort);
return $bytes_sent;
}
}
After you have your new shiny class myNewSuperDownloadHandlerClass { ... } ready, then make sure you only serve downloads through filedownload.php described here or if have done good myNewSuperDownloadHandlerClass(), then use that, just make sure that readfileWhileConnected() is used for every download requiring connection status polling.
You can easily add callback to be triggered if user closes connection, only 2 exit points here. (seen many functions that have every often return false; return true; return null; return false; return true; and so on..)

PHP filesize over 4Gb

I'm running a Synology NAS Server,
and I'm trying to use PHP to get the filesize of files.
I'm trying to find a function that will successfully calculate the filesize of files over 4Gb.
filesize($file); only works for files <2Gb
sprintf("%u", filesize($file)); only works for files <4Gb
I also tried another function that I found on the php manual, but it doesn't work properly.
It randomly works for certain file sizes but not for others.
function fsize($file) {
// filesize will only return the lower 32 bits of
// the file's size! Make it unsigned.
$fmod = filesize($file);
if ($fmod < 0) $fmod += 2.0 * (PHP_INT_MAX + 1);
// find the upper 32 bits
$i = 0;
$myfile = fopen($file, "r");
// feof has undefined behaviour for big files.
// after we hit the eof with fseek,
// fread may not be able to detect the eof,
// but it also can't read bytes, so use it as an
// indicator.
while (strlen(fread($myfile, 1)) === 1) {
fseek($myfile, PHP_INT_MAX, SEEK_CUR);
$i++;
}
fclose($myfile);
// $i is a multiplier for PHP_INT_MAX byte blocks.
// return to the last multiple of 4, as filesize has modulo of 4 GB (lower 32 bits)
if ($i % 2 == 1) $i--;
// add the lower 32 bit to our PHP_INT_MAX multiplier
return ((float)($i) * (PHP_INT_MAX + 1)) + $fmod;
}
Any ideas?
You are overflowing PHP's 32-bit integer. On *nix, this will give you the filesize as a string:
<?php $size = trim(shell_exec('stat -c %s '.escapeshellarg($filename))); ?>
How about executing a shell command like:
<?php
echo shell_exec("du 'PATH_TO_FILE'");
?>
where PATH_TO_FILE is obviously the path to the file relative to the php script
you will most probably do some regex to get the filesize as a standalone as it returns a string like:
11777928 name_of_file.extention
Here is one complete solution what you can try: https://stackoverflow.com/a/48363570/2592415
include_once 'class.os.php';
include_once 'function.filesize.32bit.php';
// Must be real path to file
$file = "/home/username/some-folder/yourfile.zip";
echo get_filesize($file);
This function can run on the 32-bit Linux
function my_file_size($file){
if ( PHP_INT_MAX > 2147483647){ //64bit
return filesize($file);
}
$ps_cmd = "/bin/ls -l $file";
exec($ps_cmd, $arr_output, $rtn);
///bin/ls -l /data/07f2088a371424c0bdcdca918a3008a9cbd74a25.ic2
//-rw-r--r-- 1 resin resin 269484032 9月 9 21:36 /data/07f2088a371424c0bdcdca918a3008a9cbd74a25.ic2
if($rtn !=0) return floatval(0);
preg_match("/^[^\s]+\s+\d+\s+[^\s]+\s+[^\s]+\s+(\d+)\s+/", $arr_output[0], $matches);
if(!empty($matches)){
return floatval($matches[1]);
}
return floatval(0);
}

Categories