3

I have a big csv file that contains an column with emails. I need to create a script that read this csv file, send an email and than remove the row. Is it possible to do without creating an temp file? If in case I store it on the database, would it be the best way to do this?

My code:

if (($handle = fopen("emails.csv", "r")) !== FALSE) {
 while (($line = fgetcsv($handle, 1000, ",")) !== FALSE) {
       $mail->parseTextandSendMail($line);
      //Need to remove the $line
  $row++;
 }
fclose($handle);

Thanks

Tiago Castro
  • 421
  • 6
  • 20
  • 2
    can't you jsut loop send, then delete the whole file, as all the emails are sent –  May 24 '16 at 21:40
  • 1
    @Dagon: That would be too easy. – AbraCadaver May 24 '16 at 21:41
  • I think database would be a good way to go. – Cave Johnson May 24 '16 at 21:46
  • @Dagon, If the server crashs I will not know which mails have been sent – Tiago Castro May 24 '16 at 21:55
  • @Andrew I could store the emails that have been sent but I would store useless data. – Tiago Castro May 24 '16 at 21:55
  • fair enough, keep a count in a separate file, when all done, delete both, if there is a crash, you can use the count to know where to restart. –  May 24 '16 at 22:00
  • If I understand files correctly, you just _can't_ delete a line from it as you go through it, because the position of every character in the file is fixed; you can overwrite a character with another character, but you can't just remove it altogether. The rest of the file won't "move up" to take the place of whatever you've deleted. – Don't Panic May 24 '16 at 22:23
  • @Don'tPanic how can I do it? – Tiago Castro May 24 '16 at 22:27
  • I think that without some version of creating a temp file, it's not possible. – Don't Panic May 24 '16 at 22:28
  • I was thinking about storing all the lines in the database in the beginning and then deleting from the database for each email sent. Or just using an extra column to mark each sent email as sent. – Cave Johnson May 24 '16 at 22:31
  • @Andrew nice idea, but is it possible to read and make another column while reding, or I would have to make before it reads? – Tiago Castro May 24 '16 at 22:47
  • You could just create the database table in phpmyadmin or whatever dbms software you use, with 3 columns (id,email,and isSent). Then read the file and for each line, store the email and set isSent to 0. Then you loop through the table and send emails. So you would have one loop to read the file into the table. And another loop to process the emails from the database. – Cave Johnson May 24 '16 at 22:50
  • Thanks @Andrew! I will do it – Tiago Castro May 24 '16 at 23:08

1 Answers1

5

It occurred to me that it could work if you read lines from the end of the file instead of the beginning. I got some help from here figuring out how to do that, and incorporated some of the code from an answer there into a function that seeks backward from the end of the file to the beginning of the last line.

function lineStart($file) {
    $position = ftell($file);
    while (fgetc($file) != "\n") {
        fseek($file, --$position);
        if ($position == 0) break;
    }
    return $position;
}

With that function, you can repeatedly read the last line end then truncate the file to the length indicated by the file position at the beginning of that line.

$file = fopen('emails.csv', 'r+');       // open for read/write

fseek($file, -1, SEEK_END);              // move to end of file

while (fstat($file)['size']) {
    lineStart($file);                    // move to beginning of line
    $line = fgetcsv($file);
    $mail->parseTextandSendMail($line);  // do your email thing
    ftruncate($file, lineStart($file));  // truncate from beginning of line
}

fclose($file);

I don't know if I think this is generally a good idea (a database seems like it would be much easier to deal with), but I just wanted to figure out if there was a way to accomplish it, and this does seem to work in my limited testing.

Community
  • 1
  • 1
Don't Panic
  • 41,125
  • 10
  • 61
  • 80
  • Thanks!!!! That is exactly what I need!!! If my server crashs I can do a cron to look for no empty files and run this script! Thanks you very much! – Tiago Castro May 25 '16 at 00:17