Need to write at beginning of file with PHP
Asked Answered
C

11

46

I'm making this program and I'm trying to find out how to write data to the beginning of a file rather than the end. "a"/append only writes to the end, how can I make it write to the beginning? Because "r+" does it but overwrites the previous data.

$datab = fopen('database.txt', "r+");

Here is my whole file:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>Facebook v0.1</title>
        <style type="text/css">
            #bod{
                margin:0 auto;
                width:800px;
                border:solid 2px black;
            }
        </style>
    </head>

    <body>
        <div id="bod">
            <?php
                $fname = $_REQUEST['fname'];
                $lname = $_REQUEST['lname'];
                $comment = $_REQUEST['comment'];
                $datab = $_REQUEST['datab'];
                $gfile = $_REQUEST['gfile'];

                print <<<form
                <table border="2" style="margin:0 auto;">
                    <td>
                        <form method="post"  action="">
                              First Name :
                              <input type ="text"
                                         name="fname"
                                         value="">
                              <br>

                              Last Name :
                                <input type ="text"
                                         name="lname"
                                         value="">
                              <br>

                              Comment :
                              <input type ="text"
                                         name="comment"
                                         value="">
                              <br>
                              <input type ="submit" value="Submit">
                        </form>
                    </td>
                </table>
                form;
                if((!empty($fname)) && (!empty($lname)) && (!empty($comment))){
                    $form = <<<come

                    <table border='2' width='300px' style="margin:0 auto;">
                        <tr>
                            <td>
                                <span style="color:blue; font-weight:bold;">
                                $fname $lname :
                                </span>

                                $comment
                            </td>
                        </tr>
                    </table>
                    come;

                    $datab = fopen('database.txt', "r+");
                    fputs($datab, $form);
                    fclose($datab);

                }else if((empty($fname)) && (empty($lname)) && (empty($comment))){
                    print" please input data";
                } // end table

                $datab = fopen('database.txt', "r");

                while (!feof($datab)){
                    $gfile = fgets($datab);
                    print "$gfile";
                }// end of while
            ?>
        </div>
    </body>
</html>
Cordy answered 19/11, 2009 at 2:30 Comment(0)
S
68

The quick and dirty:

<?php
$file_data = "Stuff you want to add\n";
$file_data .= file_get_contents('database.txt');
file_put_contents('database.txt', $file_data);
?>
Sola answered 19/11, 2009 at 2:36 Comment(6)
I think there is no better way to insert data at the beginning of the file. You have to move all the data currently contained in the file anyway. For larger files you might need to read file part by part to fit it in the memory.Heterotopia
How about using the "c" mode of fopen? Doesn't this write to the beginning of the file?Melanite
@SSHThis yes it does, but it also rewrites anything in the way :)Browse
use FILE_APPEND to avoid overwriteAviles
How big a file should this be used up to? And what about the case of multiple processes writing the file at once? Could an fopen() call with an flock() call avoid that happening?Caplin
@Fronto, would you mind elaborating about FILE_APPEND? I was unable to locate this in the PHP manual. Thank you.Juliajulian
B
47

If you don't want to load the entire contents of the file into a variable, you can use PHP's Streams feature:

function prepend($string, $orig_filename) {
  $context = stream_context_create();
  $orig_file = fopen($orig_filename, 'r', 1, $context);

  $temp_filename = tempnam(sys_get_temp_dir(), 'php_prepend_');
  file_put_contents($temp_filename, $string);
  file_put_contents($temp_filename, $orig_file, FILE_APPEND);

  fclose($orig_file);
  unlink($orig_filename);
  rename($temp_filename, $orig_filename);
}

What this does is writes the string you want to prepend to a temporary file, then writes the contents of the original file to the end of the temporary file (using streams instead of copying the whole file into a variable), and finally removes the original file and renames the temporary file to replace it.

Note: This code was originally based on a now-defunct blog post by Chao Xu. The code has since diverged, but the original post can be viewed in the Wayback Machine.

Bertrand answered 19/11, 2009 at 2:46 Comment(5)
Thx! This works very well, but only if the file exists (I had a case where the file might be missing. Really easy to work around: if (!file_exsists($filename) [...] ).Byte
PHP has tempnam() for the generation of an unique filename. md5() has a tiny risk of generating a collision with an existing file. See php.net/manual/en/function.tempnam.phpNimesh
I used this solution, but changing the $tmpname to be defined as $tmpname = tempnam(sys_get_temp_dir(), 'tmp_prepend_'); this way it uses the system folder for temp files and standard php method for temporary names, making it less prone to file system permissions errors.Wintery
@Wintery VincentNikkelen Thanks. I've updated the code.Bertrand
If you have problems with wrong permissions on the destination file (such as not being readable by Apache), try creating the temp file in the same folder as the destination instead of in a system folder. That worked for me.Wormy
G
5

I think what you can do is first read the content of the file and hold it in a temporary variable, now insert the new data to the beginning of the file before also appending the content of the temporary variable.

$file = file_get_contents($filename);
$content = 'Your Content' . $file;
file_put_contents($content);  
Gabelle answered 19/11, 2009 at 2:36 Comment(0)
S
4
  1. Open a file in w+ mode not a+ mode.
  2. Get the length of text to add ($chunkLength)
  3. set a file cursor to the beginning of the file if needed
  4. read $chunkLength bytes from the file
  5. return the cursor to the $chunkLength * $i;
  6. write $prepend
  7. set $prepend a value from step 4
  8. do these steps, while EOF

    $handler = fopen('1.txt', 'w+');//1
    rewind($handler);//3
    $prepend = "I would like to add this text to the beginning of this file";
    $chunkLength = strlen($prepend);//2
    $i = 0;
    do{
        $readData = fread($handler, $chunkLength);//4
        fseek($handler, $i * $chunkLength);//5
        fwrite($handler, $prepend);//6
    
        $prepend = $readData;//7
        $i++;
    }while ($readData);//8
    
    fclose($handler);
    
Shavonda answered 14/5, 2017 at 19:40 Comment(1)
Isn't $i * $chunkLength always 0 in this case?Billy
L
3

You can use the following code to append text at the beginning and end of the file.

$myFile = "test.csv";<br>
$context = stream_context_create();<br>
  $fp = fopen($myFile, 'r', 1, $context);<br>
  $tmpname = md5("kumar");<br>

//this will append text at the beginning of the file<br><br>
  file_put_contents($tmpname, "kumar");<br>
  file_put_contents($tmpname, $fp, FILE_APPEND);<br>
  fclose($fp);<br>
  unlink($myFile);<br>
  rename($tmpname, $myFile);<br><br>
  //this will append text at the end of the file<br>
  file_put_contents($myFile, "ajay", FILE_APPEND);
Lacerate answered 6/7, 2015 at 18:53 Comment(0)
K
2

You can use fseek to change the pointer in the note.

It has to be noted that if you use fwrite it will erase the current content. So basically you have to read the whole file, use fseek, write your new content, write the old data of the file.

$file_data = file_get_contents('database.txt')
$fp = fopen('database.txt', 'a');
fseek($fp,0);
fwrite($fp, 'new content');
fwrite($fp, $file_data);
fclose($fp);

If your file is really huge and you don't want to use too much memory, you might want to have two file approach like

$fp_source = fopen('database.txt', 'r');
$fp_dest = fopen('database_temp.txt', 'w'); // better to generate a real temp filename
fwrite($fp_dest, 'new content');
while (!feof($fp_source)) {
    $contents .= fread($fp_source, 8192);
    fwrite($fp_dest, $contents);
}
fclose($fp_source);
fclose($fp_dest);
unlink('database.txt');
rename('database_temp.txt','database.txt');

The solution of Ben seems to be more straightforward in my honest opinion.

One last point: I don't know what you are stocking in database.txt but you might do the same more easily using a database server.

Keeleykeelhaul answered 19/11, 2009 at 2:44 Comment(0)
L
2

One line:

file_put_contents($file, $data."\r\n".file_get_contents($file));

Or:

file_put_contents($file, $data."\r\n --- SPLIT --- \r\n".file_get_contents($file));
Lunchroom answered 1/2, 2020 at 8:48 Comment(0)
N
1

There is no way to write to the beginning of a file like you think. This is I guess due to reason how OS and HDD are seeing the file. It has got a fixed start and expanding end. If you want to add something in the middle or beggining it requires some sliding. If it is a small file just read it all and do your manipulation and write back. But if not, and if you are always adding to the beginning just reverse line order, consider the end as beginning...

Nasturtium answered 19/11, 2009 at 2:43 Comment(0)
H
1

This code remembers data from the beginning of the file to protect them from being overwritten. Next it rewrites the all the data existing in file chunk by chunk.

$data = "new stuff to insert at the beggining of the file";
$buffer_size = 10000;

$f = fopen("database.txt", "r+");
$old_data_size = strlen($data);
$old_data = fread($f, $old_data_size);
while($old_data_size > 0) {
  fseek($f, SEEK_CUR, -$old_data_size);
  fwrite($f, $data);
  $data = $old_data;
  $old_data = fread($f, $buffer_size);
  $old_data_size = strlen($data);
}
fclose($f);
Heterotopia answered 19/11, 2009 at 2:55 Comment(0)
W
0

file_get_contents() and file_put_contents() use more memory than using the fopen(), fwrite(), and fclose() functions:

$fh = fopen($filename, 'a') or die("can't open file");
fwrite($fh, $fileNewContent);
fclose($fh);
Wenwenceslaus answered 27/5, 2015 at 10:2 Comment(1)
This does not say anything about the "prepending" functionality the OP was asking..Fretwork
T
0

It's worth mentioning that if you want to add a line to a .sql dump file, you can tell mysqldump to append to a file instead of overwrite using >> instead of >.

So you could do...

file_put_contents('dump.sql', 'DROP DATABASE some_db;' . "\r\n");
exec('mysqldump -u user -ppassword database >> dump.sql')
Tamaru answered 11/7 at 15:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.