I run a small website and my users requested that I set up a mailing list. I found a simple free script that adds e-mail addresses to a protected text file, email.txt
, in CSV format:
email1@yahoo.com,email2@yahoo.com,blah,blah,blah
The script works flawlessly. However, it is a nuisance to go through the file to manually remove e-mail addresses when users cancel their list subscriptions. I need to create a simple script that removes e-mail addresses.
All I want is a simple PHP script that displays a text box so users can enter their e-mail addresses and click a "Cancel Newsletter" button. The script should search the text file, find the given e-mail address and remove it and its trailing comma.
For example, say the contents of email.txt
are
john@yahoo.com,peter@yahoo.com,steve@yahoo.com
If I type "peter@yahoo.com" into the text box displayed by my desired script, I want the file to look like this:
john@yahoo.com,steve@yahoo.com
UPDATE: I tried this code:
<?php
function showForm() {
echo '
<form method="post" action="">
Email Address: <input type="text" name="email"> <br />
<input type="submit" value="Cancel Newsletter" name="submit">
</form>
';
}
$_POST['email']
$to_delete = 'email';
$file = array_flip(explode(",",file_get_contents("email.txt")));
unset($file[$to_delete]);
file_put_contents("email.txt",implode(",",array_flip($file));
if(!$file_put_contents) {
die('Error occured');
} else {
echo 'Your subscription has been cancelled. You will not receive any further emails from us.';
}
}
} else {
showForm();
}
?>
This code doesn't even show the form.
UPDATE 2:
Another attempt at writing this script:
<?php
$email = $_POST["email"];
$text = file_get_contents("email.txt");
$oldWord = "$email";
$newWord = "";
$text = str_replace($oldWord , $newWord , $text);
$fp = fopen('email.txt', 'w');
fwrite($fp, $text);
fclose($file);
?>
This works as far as removing the e-mail address goes, but there is no announcement (echo). I would like for it to say either "that e-mail isn't subscribed" or "you have been removed," based on whether the script sucessfully finds the $email
in the list and deletes it.
UPDATE 3 Dec. 31, 2011:
I tried the advanced code and just got a blank page, so I went back to my version. Here is the code I have now:
<html>
<body>
<form method="post" action="">
<p>Email Address: <input type="text" name="email"></p>
<input type="submit" value="Cancel Newsletter" name="submit">
</form>
<?php
$email = $_POST["email"];
$basetext = file_get_contents("email.txt");
$oldWord = "$email";
$newWord = "";
$text = str_replace($oldWord , $newWord , $basetext);
$str1 = $basetext;
// echo strlen($str1);
$str2 = $text;
// echo strlen($str2);
$fp = fopen('email.txt', 'w');
fwrite($fp, $text);
if ($str1 > $str2) { // This part handles the success/fail message
echo ("Success!");
} else {
echo ("Fail!");
}
fclose($file);
?>
</body>
</html>
This works perfectly. However, it displays the "fail" message when the page is loaded, not when triggered to load, after the submit button is pressed.
I would like to keep the original code if possible, just rearranged so that it only shows "Success!" or "Fail!" once it has executed the code.
I would like the echo messages to be the last script executed on the page.
Suggested research:
http://us.php.net/manual/en/function.explode.php
http://us3.php.net/manual/en/function.file-put-contents.php
edited to add: http://us3.php.net/manual/en/function.file-get-contents.php
If you end up with a 3rd party service, don't pay Aweber. Go for MailChimp. They've got a free plan if your mailing list isn't that big.
In your sample you reference a variable
$_POST['email']
without assignment or testing the value. Additionally you may want to sanitize this variable.Another issue I saw was that
$to_delete = 'email';
, you are only looking for entries of 'email'.Your
$file_put_contents
is not being assigned.} else { showForm(); }
wasn't paired up with an if statement.This answer was originally appended to the question body by the OP.
First I moved the form to
/cancel.html
and used<form action="/cancel_submit.html">
.(Where I have written
.html
, it is just to demonstrate, as my server is configured to use no page extentions and also so that PHP is parsed on.html
pages.)Then I put the PHP code into the page
/cancel_submit.html
and movedto another set of PHP brackets.
This meant that the e-mail affffdress was sent via POST to the other page, which then performed the actual removal of the e-mail address from the list and then checked to see if an address been removed to provide the comfirmation message.
I also added two commas to
$oldword = "$email";
to make it$oldword = ",$email,";
so that it only finds the text entered into the e-mail box if it has a comma on either side. This addresses the case where someone submits half of an e-mail address.I also changed
$newWord = "";
to$newWord = ",";
so that if the script removes an e-mail address with commas at each side, the two e-mail addresses that were next to it will not be separated by a comma.Here is the code I have for both pages now:
cancel.html
cancel_submit.html
EDIT:
I made a few improvements. I added:
to both the e-mail add script and the e-mail remove script. This converted all characters entered into either form to lowercase; previously, it wouldnt remove e-mails typed in a different case than the big list had.
This messed up the confirmation message command, so I changed it to
Is there any reason why you don't use a database?
These are just infinitely easier and more efficient than a text file...
But if you want to use a text file...
Basically what it does it explodes by the comma, then flips the array so that the emails are keys (and their numeric positions are values, but that doesn't matter), then it removes the email you want to delete and finally reassembles the file. The bonus of this is that it will also strip out any duplicates you may have.
You can use a similar method to add email addresses, just changing the
unset
line to$file['user1@example.com'] = -1;
(to ensure the number doesn't conflict with anything, as that would interfere with the array flipping).If I understand your question correctly, this is what you are attempting to achieve.
I know this can be done as a very simple task, but I don't trust that approach. Additionally, I think anything interacting with permanent storage of data should have some mild to moderate form of abstraction.
I would approach that task this way.