I'm trying to combine two CSV files in PHP. I'm looking for perfect method. Here's my code so far:
$one = fopen('data5.csv', 'r');
$two = fopen('userdata.csv', 'r');
$final = fopen('final_data.csv', 'a');
$temp1 = fread($one, filesize("data5.csv"));
$temp2 = fread($two, filesize("userdata.csv"));
fwrite($final, $temp1);
fwrite($final, $temp2);
I will give you a solution to use if you have big CVSs and you don't want to use much of your machine's RAM (imagine each CSV is 1GB, for example).
<?php
function joinFiles(array $files, $result) {
if(!is_array($files)) {
throw new Exception('`$files` must be an array');
}
$wH = fopen($result, "w+");
foreach($files as $file) {
$fh = fopen($file, "r");
while(!feof($fh)) {
fwrite($wH, fgets($fh));
}
fclose($fh);
unset($fh);
fwrite($wH, "\n"); //usually last line doesn't have a newline
}
fclose($wH);
unset($wH);
}
Usage:
<?php
joinFiles(array('join1.csv', 'join2.csv'), 'join3.csv');
Fun fact:
I just used this to concat 2 CSV files of ~500,000 lines each. It took around 5seconds and used 512kb of memory.
Logic:
Open each file, read one line and then write it to the output file. Yes, it may be slower writing each line rather than writing a whole buffer, but this allows the usage of heavy files while being gentle on the memory of the machine.
At any point, you are safe because the script only reads on line at a time and then writes it.
Enjoy!
How about...
file_put_contents('final_data.csv',
file_get_contents('data5.csv') .
file_get_contents('userdata.csv')
);
Note that this loads the entire files into PHP memory though. So, if they are big, you may get memory_limit issues.
If you want to just concatenate the two files you can do this easily with executing a shell script assuming you are on unix like os:
exec("cat data5.csv > final_data.csv && cat userdata.csv >> final_data.csv");
ob_start();
$dir1 = "csv/2014-01/";
$dir = $_REQUEST['folder_name'];
$totalfiles = count(glob($dir."/*",GLOB_BRACE));
echo "Total files in folder = ".$totalfiles;
if ($opend = opendir($dir)){
$i =0; $final_array_export= array();
$fil_csv =end(explode('/',$dir));
$file_name = 'download/'.$fil_csv.'.csv';
$file_cre = fopen($file_name,"w");
$headers = array("header1","header2");
fputcsv($file_cre,$headers);
while (($file = readdir($opend)) !== false){
$filename = $dir.'/'.$file;
$files = fopen($filename,"r");
if($files){
$fullarray = fgetcsv($files);
$head=array();
if(count($fullarray) >0){
foreach($fullarray as $headers){
$head[] = $headers;
}
}
while($data = fgetcsv($files,0,",")){
if(count($data) >0 && count($head) >0){
$array_combine = array_combine($head,$data);
}
fputcsv($file_cre,$array_combine);
}
}
}
fclose($file_cre);
header("Content-Type: application/force-download");
header("Content-type: application/csv");
header('Content-Description: File Download');
header('Content-Disposition: attachment; filename=' . $file_name);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-length: ' . filesize($file_name));
ob_clean();
flush();
readfile($file_name);
}
Related
I want to edit certain parts of a file before it gets downloaded. I want to do it via php, but i can live with javascript or flash. How wold i do it?
this is how i tried it, but it replaces the whole line and also doesnt revert back to the original
<?php
$file = 'folder/file.ext';
if($_POST['filename'] != null)
{
$exclude = "text";
$lines = file($file);
$out = $_POST['filename'];
foreach ($lines as $line) {
if (strstr($line, $exclude) == "") {
$out .= $line;
}
}
$f = fopen($file, "w");
fwrite($f, $out);
fclose($f);
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="text.php"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
$exclude = $_POST['filename'];
$lines = file($file);
$out = "text";
foreach ($lines as $line) {
if (strstr($line, $exclude) == "") {
$out .= $line;
}
}
$f = fopen($file, "w");
fwrite($f, $out);
fclose($f);
}
}
?>
For this you want to learn about a few things. The first being mod_rewrite, which allows "URL Rewriting". What you can do with this, is you can make it so that when a user tried to access "http://example.com/files/file-123.txt", instead they get "http://example.com/download.php?file=file-123.txt". They won't know that they're hitting the PHP Script, but they do.
Using this, on download.php, you can do something like
$file = $_GET['file'];
if (file_exists($file))
{
//Put your headers here
$contents = file_get_contents($pathToFile);
//Do your replacements in $contents here, but don't write to the file
echo $contents;
}
And that way you're only modifying the file that gets sent to the user, not the file that's on your server itself.
Keep in mind that this doesn't outlay any security issues that you'll need to fix. There are a lot of them when you're doing file access, such as making sure that $_GET['file'] is a file that they're actually allowed to access, and not say "/etc/sudoers".
But I think this is the approach that you'd like to take, yes?
I think you have to download file and then modify it and save.
To read particular part of the file use fgets($file, position)
If you want to place content in particular position try fseek()
If you want just append file_put_content($file, $content, FILE_APPEND);
I have an issue while downloading an mp3 file in PHP. I need to download the file, also rename it. Below is the download.php file which contains the following code:
$file = $_GET['file'];
$flname = explode("/",$file);
$num = sizeof($flname);
$filenme = $flname[$num-1];
$name_of_file = $filenme;
header('Content-Description: File Transfer');
header('Content-type: application/mp3');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Content-Length: '.filesize($name_of_file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
readfile_chunked($file);
function readfile_chunked($file)
{
$chunksize = 1*(1024*1024); // how many bytes per chunk
$buffer = '';
$handle = fopen($filename, 'rb');
if ($handle === false)
{
return false;
}
while (!feof($handle))
{
$buffer = fread($handle, $chunksize);
print $buffer;
}
return fclose($handle);
}
I am getting the file path in $file:
$file = $_GET['file'];
where $file becomes:
$file = "localhost/project/mp3 file path";
Then I am exploding it to get the mp3 file name only (thus removing the path).
I don't know what the problem is, but it's always showing some 490 bytes in the download dialogue of Firefox even if file is of 1-2MB. Can someone explain what I'm doing wrong?
Thank you in advance.
Open the downloaded file in a text editor. It probably contains php errors that will tell you what exactly is going on. It might be an issue with the path or permissions of the file you are trying to download.
Hey i have following code to download a large file but the download does stop everytime without finish the download
function download($file)
{
include('logger.php5');
$log = new Logging();
$log->lfile('download.log');
ini_set('max_execution_time', 86400);
//header('Location: '.$file);
$filesize = filesize($file);
$filename = pathinfo($file, PATHINFO_BASENAME);
$filext = pathinfo($file, PATHINFO_EXTENSION);
$mime = include('mime.php5');
$log->lwrite(ini_get('max_execution_time'));
$log->lwrite(sprintf('%s %s %s %s', $filename, $filext, $mime[$filext], human_filesize($filesize)));
$log->lclose();
#ob_end_clean();
session_write_close();
header("Content-Description: File Transfer");
header("Content-Type: ".$mime[$filext]);
header("Content-Disposition: ".
(!strpos($HTTP_USER_AGENT,"MSIE 5.5")?"attachment; ":"").
"filename=".$filename);
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$filesize);
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header('Pragma: public');
header('Expires: 0');
$done = readfile_chunked($file);
}
function readfile_chunked($filename,$retbytes=true) {
$chunksize = 1*(1024*1024); // how many bytes per chunk
$buffer = '';
$cnt =0;
// $handle = fopen($filename, 'rb');
$handle = fopen($filename, 'rb');
if ($handle === false) {
return false;
}
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status;
}
Each time i call the script the download start up but stops after 400MB, the file itself is 778MB big.
Someone can see a problem with the code?
UPDATE
after try to log the return value of readfile_chunkedit feels like the script gets stoped not the download itself. Because i cant get a log entry after the readfile_chunked call.
It could be a problem with the filesize function in PHP. There are known bugs for big file size reading and as you're sending it with the file as an header I would suggest you to try the script without using this line:
header("Content-Length: ".$filesize);
Oh and maybe you can take a look at this line:
header("Content-Transfer-Encoding: binary");
I think the encoding should be checked for each file. Like this:
$finfo = finfo_open(FILEINFO_MIME);
//check to see if the mime-type starts with 'text'
return substr(finfo_file($finfo, $filename), 0, 4) == 'text';
If it's a textfile you should use ASCII ofcourse. Has nothing to do with the question but I think it's an useful addition to your script :)
when i use this phpcode to download a file with a downloadspeed of 300Kb/s i use this:
function readfile_chunked($dl_link, $filesize_file) {
$chunksize = 300*1024; #Buffersize in Byte
$data = '';
$handle = fopen($dl_link, 'rb');
while (!feof($handle)) {
$data = fread($handle, $chunksize);
sleep(1);
print $data;
#ob_flush();
#flush();
}
fclose($handle);
}
But it doesn´t work! :-(
When i start the Download, the speed is under one KB/s and it breaks and then resume, and so on.
When i take off this "sleep(1)" in the code above, then the download starts and all is good, but it runs with fullspeed. -> logical!
Why is this?
That looks mostly okay, however try the following:
function readfile_chunked($path, $speed)
{
if (is_file($path) !== true)
{
exit('not a local file');
}
header('Pragma: public');
header('Cache-Control: public, no-cache');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . filesize($path));
header('Content-Disposition: attachment; filename="' . basename($path) . '"');
header('Content-Transfer-Encoding: binary');
$handle = fopen($path, 'rb');
while (!feof($handle))
{
echo fread($handle, $speed * 1024); sleep(1);
while (ob_get_level() > 0)
{
ob_end_flush();
}
flush();
}
fclose($handle);
}
readfile_chunked('/path/to/your/file.ext', 300);
You may want to try adding #ob_flush_end() at first to disable output buffering, and remove #ob_flush() in the loop. The delay may be because of the output buffering.
You may also try replacing print with echo. You may gain some performance improvement.
Also try a smaller chunk and use usleep instead for a shorter delay time.
I use the following to download a file with PHP:
ob_start();
$browser = id_browser();
header('Content-Type: '.(($browser=='IE' || $browser=='OPERA')?
'application/octetstream':'application/octet-stream'));
header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize(realpath($fullpath)));
//header("Content-Encoding: none");
if($browser == 'IE')
{
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
} else
{
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
}
//#set_time_limit( 0 );
ReadFileChunked(utf8_decode($fullpath));
ob_end_flush();
The source code of ReadFileChunked is:
function ReadFileChunked($filename,$retbytes=true)
{
$chunksize = 1*(1024*1024);
$remainFileSize = filesize($filename);
if($remainFileSize < $chunksize)
$chunksize = $remainFileSize;
$buffer = '';
$cnt =0;
// $handle = fopen($filename, 'rb');
//echo $filename."<br>";
$handle = fopen($filename, 'rb');
if ($handle === false) {
//echo 1;
return false;
}
//echo 2;
while (!feof($handle))
{
//echo "current remain file size $remainFileSize<br>";
//echo "current chunksize $chunksize<br>";
$buffer = fread($handle, $chunksize);
echo $buffer;
sleep(1);
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
$remainFileSize -= $chunksize;
if($remainFileSize == 0)
break;
if($remainFileSize < $chunksize)
{
$chunksize = $remainFileSize;
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status;
}
The question is :
The file downloaded will contiain some html tags which are the content of the html code generated by the php.
The error will happened when downloading the txt file with the file size smaller than 4096 bytes.
Please help me to slove this problem , thank you very much!
Chu
Have you tried using fpassthru rather than your custom function.
There's no need to use the $chunksize stuff in there. fread() automatically stops reading once it reaches the end of the file, even if the $chunksize would normally tell it to read more. As well, you should probably put your ob_flush() and flush() calls BEFORE the sleep(1). That way the data you've just placed in the output buffer can get sent off to the webserver without having to wait the one second needlessly.
In fact, you could replace the whole function with the following:
function ReadFileChunk($filename, $retbytes = true) {
$fh = fopen($filename, 'rb');
if (!$fh) {
return(false);
}
while($buf = fread($fh, 4096)) {
echo $buf;
ob_flush();
flush();
sleep(1);
}
$status = fclose($fh);
return( $retbytes ? filesize($filename) : $status);
}
But why bother rolling your own when readfile() already exists? It will handle the whole business of opening the file, and sending it in normal-sized pieces that won't exceed memory_limit.