Multipart email form με ελληνικά και greeklish

Μια περιοχή όπου τα μέλη μας μπορούν να βάζουν τα PHP scripts που έχουν φτιάξει και θέλουν να τα μοιραστούν με τα υπόλοιπα μέλη.

Συντονιστές: WebDev Moderators, Super-Moderators, PHP Moderators

Απάντηση
Άβαταρ μέλους
mrpc
WebDev Moderator
Δημοσιεύσεις: 3393
Εγγραφή: 03 Μάιος 2000 03:00
Τοποθεσία: Εξάρχεια
Επικοινωνία:

Multipart email form με ελληνικά και greeklish

Δημοσίευση από mrpc » 20 Αύγ 2005 07:27

Πρόσφατα μου ζητήθηκε να φτιάξω μια εφαρμογή αποστολής email (για mailing list) η οποία θα μεταφράζει αυτόματα τα ελληνικά σε greeklish και θα στέλνει ένα multipart email το οποίο θα περιέχει Ελληνικά και Greeklish σε html και plain text.
Έφτιαξα λοιπόν ένα μικρό δείγμα το οποίο ίσως να βοηθήσει κάποιους. Βέβαια ο κώδικας είναι γραμμένος πολύ βιαστικά.

Ξεκινάμε λοιπόν φτιάχνοντας μια απλή html σελίδα με μια φόρμα που θα δέχεται τα στοιχεία που δίνουμε:

Κώδικας: Επιλογή όλων

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http&#58;//www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Greeklish stuff</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-7">
<style type="text/css">
<!--
.style1 &#123;font-size&#58; small&#125;
-->
</style>
</head>
<body>
<form name="form1" method="post" action="">
  <p> Αποστολέας&#58;
<input name="from" type="text" id="from">
    <br>
    Θέμα&#58;
    <input name="title" type="text" id="title">
    <br>
    Προς&#58;
    <input name="to" type="text" id="to" ">
  </p>
  <p>Μήνυμα <span class="style1">&#40;Ελληνικά - html&#41;</span> &#58; </p>
  <p>
    <textarea name="text" rows="10" cols="50" id="text">
  </textarea> 
  </p>
  <p>
    <input type="submit" name="Submit" value="Submit">
  </p>
</form>
</body>
</html>
Μια απλή Post φόρμα, η οποία επειδή δεν έχει δηλωμένο action, με το submit θα ξαναφορτώσει την ίδια σελίδα, αλλά με τα στοιχεία που θέλουμε.
Πριν δούμε τι θα κάνουμε με αυτά τα στοιχεία, καλό είναι να προσθέσουμε ένα τυπικό validation:

Κώδικας: Επιλογή όλων

<?
if &#40;$_POST&#91;'to'&#93;&#41;&#123;
$Email_to = $_POST&#91;'to'&#93;;			// Που θα πάει το mail
&#125;
else &#123;
$Email_to = '';
&#125;
if &#40;$_POST&#91;'title'&#93;&#41; &#123;
$Email_subject = $_POST&#91;'title'&#93;;			// Θέμα

&#125;
else &#123;
$Email_subject = '';		
&#125;
if &#40;$_POST&#91;'from'&#93;&#41;&#123;
$from = $_POST&#91;'from'&#93;;		// Αποστολέας
&#125;
else &#123;
$from = "";
&#125;
if &#40;isset&#40;$_POST&#91;'text'&#93;&#41;&#41; &#123;
$text = $_POST&#91;'text'&#93;;
&#125;
else &#123;
$text ="";
&#125;
$error = 0;
if &#40;$Email_to == ""&#41; &#123;
?> <b>ΔΕΝ ΕΧΕΤΕ ΕΙΣΑΓΕΙ ΔΙΕΥΘΥΝΣΗ ΠΑΡΑΛΗΠΤΗ</b><? 
$error = 1;
&#125;
if &#40;$Email_subject == ""&#41; &#123;
?> <b>ΔΕΝ ΕΧΕΤΕ ΕΙΣΑΓΕΙ ΘΕΜΑ</b><? 
$error = 1;
&#125;
if &#40;$from == ""&#41; &#123;
?> <b>ΔΕΝ ΕΧΕΤΕ ΔΙΕΥΘΥΝΣΗ ΑΠΟΣΤΟΛΕΑ</b><? 
$error = 1;
&#125;
if &#40;$text == ""&#41; &#123;
?> <b>ΔΕΝ ΕΙΣΑΓΕΙ ΚΕΙΜΕΝΟ</b><?
$error = 1; 
&#125;
?>
Στον παραπάνω κώδικα ορίσαμε τις μεταβλητές μας για να μπορέσουμε να επεξεργαστούμε τα data που παίρνουμε από τη φόρμα και ελέγχουμε αν έχουμε ό,τι χρειαζόμαστε. Αν κάτι λείπει βγαίνει αντίστοιχο μήνυμα.
Επίσης έχουμε τη μεταβλητή $error η οποία αν όλα πάνε καλά θα πρέπει να είναι 0, σε οποιοδήποτε λάθος αλλάζει τιμή. Θα μας χρειαστεί αργότερα.
Φυσικά αφού έχουμε τις μεταβλητές, μπορούμε να τις χρησιμοποιήσουμε και στη φόρμα μας για να βλέπει ο χρήστης τι έχει εισάγει ήδη. Έτσι λοιπόν αντίστοιχα τις γραμμές:

Κώδικας: Επιλογή όλων

<input name="from" type="text" id="from"> 

Κώδικας: Επιλογή όλων

<input name="title" type="text" id="title">

Κώδικας: Επιλογή όλων

<input name="to" type="text" id="to" ">

Κώδικας: Επιλογή όλων

   <textarea name="text" rows="10" cols="50" id="text"></textarea>
σε:

Κώδικας: Επιλογή όλων

<input name="from" type="text" id="from" value="<?=$from?>">

Κώδικας: Επιλογή όλων

<input name="title" type="text" id="title" value="<?=$Email_subject?>">

Κώδικας: Επιλογή όλων

<input name="to" type="text" id="to" value="<?=$Email_to?>">

Κώδικας: Επιλογή όλων

<textarea name="text" rows="10" cols="50" id="text"><?=$text?>
  </textarea>
Τώρα το πρώτο πρόβλημα που αντιμετωπίζουμε είναι η μετατροπή των ελληνικών σε greeklish. Η πιο γρήγορη λύση είναι η function str_replace.
Η σύνταξή της σύμφωνα με το manual έχει ως εξής:

Κώδικας: Επιλογή όλων

str_replace &#40; mixed search, mixed replace, mixed subject &#91;, int &count&#93; &#41;
Για τα search και replace μπορούμε να χρησιμοποιήσουμε arrays. Έτσι φτιάχνουμε ένα array με όλους τους ελληνικούς χαρακτήρες, κεφαλαίους, πεζούς, τονισμένους, με διαλυτικά, αι, οι, ου κλπ, και ένα δεύτερο array με τους αγγλικούς χαρακτήρες που θα αντικαταστήσουν τους ελληνικούς.
προσθέτουμε λοιπόν πριν το ?> στο τέλος του προηγούμενου κώδικα:

Κώδικας: Επιλογή όλων

$greekfind = array&#40;"αι", "οι", "ου", "ει", "ευ", "αυ",
					"Α", "Β", "Γ", "Δ", "Ε", "Ζ", "Η", "Θ", "Ι", "Κ", "Λ", "Μ", "Ν", "Ξ", "Ο", "Π", "Ρ", "Σ", "Τ", "Υ", "Φ", "Χ", "Ψ", "Ω",
					"α", "β", "γ", "δ", "ε", "ζ", "η", "θ","ι", "κ", "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "σ", "τ", "υ", "φ", "χ", "ψ", "ω",
					"Ά", "ά", "Έ", "έ", "Ή", "ή", "Ί", "ί", "Ό", "ό", "Ύ", "ύ", "Ώ", "ώ", "ΐ", "ΰ", "ϊ", "ϋ", "ς"&#41;;
					
$greekreplace = array &#40;"ai", "oi", "ou", "ei", "ef", "af",
						"A", "V", "G", "D", "E", "Z", "I", "Th", "I", "K", "L", "M", "N", "X", "O", "P", "R","S","T","I","F","H", "Ps", "W",
						"a", "v", "g", "d", "e", "z", "i", "th", "i", "k", "l","m","n","x","o","p","r","s","t","i","f","h","ps","w",
						"a","a","e","e","i","i", "i", "i", "o", "o", "i", "i", "w", "w", "i", "i", "i", "i", "s"&#41;;
$greeklish = str_replace &#40;$greekfind, $greekreplace, $text&#41;;
Έτσι τώρα έχουμε όλο το ελληνικό κείμενο στη μεταβλητή $text και όλο το greeklish στη μεταβλητή $greeklish. Νομίζω πως είναι πολύ απλό μέχρι εδώ.
Όμως έχουμε άλλο ένα ζητούμενο. Ως εδώ έχουμε το κείμενό μας κανονικά με όλα τα html tags του. Τι γίνεται με την plain text έκδοσή του;
Θα χρειαστούμε άλλη μια λειτουργία για να αφαιρέσουμε όλα τα html tags.
Ο τρόπος για να το κάνουμε είναι ανάλογος με τη μετατροπή σε greeklish, μόνο που τώρα θα χρησιμοποιήσουμε την preg_replace, η οποία αντί να ψάχνει για strings, ψάχνει για regular expressions.
Έτσι προσθέτουμε, πάλι πριν το ?>, τον παρακάτω κώδικα (τον οποίο μπορείτε να βρείτε σε 100δες εφαρμογές php και φυσικά τον πήρα από μια από αυτές):

Κώδικας: Επιλογή όλων

$search = array &#40;"'<script&#91;^>&#93;*?>.*?</script>'si",  // Strip out javascript
                 "'<&#91;/!&#93;*?&#91;^<>&#93;*?>'si",          // Strip out HTML tags
                 "'&#40;&#91;rn&#93;&#41;&#91;s&#93;+'",                // Strip out white space
                 "'&&#40;quot|#34&#41;;'i",                // Replace HTML entities
                 "'&&#40;amp|#38&#41;;'i",
                 "'&&#40;lt|#60&#41;;'i",
                 "'&&#40;gt|#62&#41;;'i",
                 "'&&#40;nbsp|#160&#41;;'i",
                 "'&&#40;iexcl|#161&#41;;'i",
                 "'&&#40;cent|#162&#41;;'i",
                 "'&&#40;pound|#163&#41;;'i",
                 "'&&#40;copy|#169&#41;;'i",
                 "'&#&#40;d+&#41;;'e"&#41;;                    // evaluate as php

$replace = array &#40;"",
                 "",
                 "\1",
                 "\"",
                 "&",
                 "<",
                 ">",
                 " ",
                 chr&#40;161&#41;,
                 chr&#40;162&#41;,
                 chr&#40;163&#41;,
                 chr&#40;169&#41;,
                 "chr&#40;\1&#41;"&#41;;
$nohtmlgreeklish = preg_replace&#40;$search, $replace, $greeklish&#41;;
$nohtml = preg_replace&#40;$search, $replace, $text&#41;;
Τώρα έχουμε άλλες δύο μεταβλητές:
την $nohtmlgreeklish που έχει το greeklish κείμενο σε plain text και
την $nohtml που έχει το ελληνικό κείμενο σε plain text.
Και φτάνουμε στο τελευταίο κομμάτι του κώδικα που είναι η δημιουργία και η αποστολή του email.
Όπως είπαμε θέλουμε να στείλουμε ένα Multipart email, το οποίο θα περιέχει και την plain text και την html έκδοση του κειμένου, και ο κάθε email client θα αποφασίζει τι θα εμφανίσει αυτόματα.
Πάλι λοιπόν πριν το ?> τοποθετούμε τον παρακάτω κώδικα:

Κώδικας: Επιλογή όλων

$semi_rand = md5&#40;time&#40;&#41;&#41;;
$Email_boundary = "==Multipart_Boundary_x&#123;$semi_rand&#125;x"; 
 $Email_body_text = "Ελληνικά\n\n$nohtml\n\n\nGreeklish\n\n$nohtmlgreeklish";
$Email_body_html = "<b>Ελληνικά</b><br><Br>".nl2br &#40;$text&#41;."<br><BR><Br><b>Greeklish</b><br><Br>".nl2br&#40;$greeklish&#41;;
 $Email_body = 'Content-Transfer-Encoding&#58; 7bit' .
 "\r\n\r\n$nohtmlgreeklish\r\n\r\n" .
'--' . $Email_boundary . "\r\n" .
'Content-Type&#58; text/plain;
charset="iso-8859-7"' . "\r\n" .
'Content-Transfer-Encoding&#58; 7bit' .
"\r\n" .
"\r\n" .
$Email_body_text . "\r\n" .
"\r\n" .
'--' . $Email_boundary . "\r\n" .
'Content-Type&#58; text/html; charset="iso-8859-7"' . "\r\n" .
'Content-Transfer-Encoding&#58; 7bit' .
"\r\n\r\n" .
'<html>' . "\r\n" .
'<body>' . "\r\n" .
'<p>' . $Email_body_html . '</p>' .
"\r\n" .
'</body>' . "\r\n" .
'</html>' . 
"\r\n" .
'--' . $Email_boundary . "--" ;

$Email_headers = 'From&#58; ' . "$from\r\n" .
'Reply-To&#58; ' . "$from\r\n" .
'MIME-Version&#58; 1.0' . "\r\n" .
'X-Mailer&#58; PHP/' . phpversion&#40;&#41; . "\r\n" .
'Content-Type&#58; multipart/alternative; boundary="' . $Email_boundary . "\";\r\n";
if &#40;$error ==0&#41;&#123;
	if &#40;mail&#40;$Email_to, $Email_subject, $Email_body, $Email_headers&#41;&#41; &#123;
		?> <b>Το μήνυμα στάλθηκε επιτυχώς</b><? 
		&#125;
	&#125;
Τα πράγματα φαίνονται μπερδεμένα, όμως δεν είναι.
Για να στείλουμε το email χρησιμοποιούμε την mail () στην οποία δίνουμε 4 παραμέτρους: τον παραλήπτη, το θέμα, το περιεχόμενο του μηνύματος και τους headers.
Για να μπορέσουμε να αναλύσουμε πως δουλεύει θα προσθέσουμε τα παρακάτω στο Html κομάτι του script μας, πριν από το </body>.

Κώδικας: Επιλογή όλων

<p>Greeklish&#58;</p>
<p>
  <textarea readonly name="textarea" rows="10" cols="50"><?=$greeklish?>
  </textarea>
</p>
<p>Ελληνικά χωρίς html &#58;</p>
<p>
  <textarea readonly name="textarea2" rows="10" cols="50"><?=$nohtml?>
  </textarea>
</p>
<p>Greeklish χωρίς html&#58;</p>
<p>
  <textarea readonly name="textarea3" rows="10" cols="50"><?=$nohtmlgreeklish?>
  </textarea>
</p>
<p>Message Body&#58;</p>
<p>
  <textarea readonly name="textarea4" rows="10" cols="50"><?=$Email_body?>
  </textarea>
</p>
<p>Message Headers&#58; </p>
<p>
  <textarea readonly name="textarea5" rows="10" cols="50"><?=$Email_headers?>
  </textarea> 
</p>
<p>&nbsp;</p>
Έτσι δοκιμάζοντας να στείλουμε ένα email με το κείμενο test, θα δούμε κάποιες επιπλέον πληροφορίες, τα headers και το περιεχόμενο του mail όπως το στέλουμε. (επίσης για ευκολία έχω προσθέσει σε text area όλες τις μορφές του κειμένου που θα φύγει).
Βλέπουμε στα headers τα παρακάτω:
From: χχχχ@χχχχ.com
Reply-To: χχχχχχ@χχχχχ.com
MIME-Version: 1.0
X-Mailer: PHP/4.3.11
Content-Type: multipart/alternative; boundary="==Multipart_Boundary_xfb728be978e3933c9478450b61e21b72x";
Η έκδοση MIME χρειάζεται για να ξέρει ο email client πως θα διαχειριστεί τα δεδομένα. Επίσης του ορίζουμε ότι το περιεχόμενο είναι τύπου multipart/alternative, δηλαδή εναλακτικές εκδόσεις του content.
Τέλος ορίζουμε το boundary, το οποίο είναι ίσως και το πιο βασικό κομάτι.
Ουσιαστικά είναι ένα String το οποίο όταν το βλέπει ο client καταλαβαίνει ότι έχει αρχίσει ένα άλλο part του content μας. Μπορεί να είναι οποιοδήποτε string, όμως για να είμαστε σίγουροι ότι δεν θα εισαχθεί τυχαία στο κείμενο του email μπερδεύοντας έτσι τον client, βάζουμε κάτι που είναι αδύνατον να το πετύχει κανείς στην τύχη.
Στο συγκεκριμένο παράδειγμα χρησιμοποιώ το τρέχον unix timestamp σε md5:

Κώδικας: Επιλογή όλων

$semi_rand = md5&#40;time&#40;&#41;&#41;;
$Email_boundary = "==Multipart_Boundary_x&#123;$semi_rand&#125;x"; 
Πάμε τώρα να δούμε και το message body.
Σε κάθε μέρος του body ορίζουμε και κάποια headers για το συγκεκριμένο κομάτι. Στην αρχή το:
Content-Transfer-Encoding: 7bit

test
το οποίο δεν περιέχει το boundary string, χρησιμοποιείται από τους email clients που δεν υποστηρίζουν multipart μηνύματα. Ότι βάλουμε σε αυτό το κομάτι θα εμφανίζεται μόνο από αυτούς. Για αυτό εμείς εμφανίζουμε το greeklish κείμενο χωρίς html tags, μέσα από τις γραμμές:

Κώδικας: Επιλογή όλων

 $Email_body = 'Content-Transfer-Encoding&#58; 7bit' .
 "\r\n\r\n$nohtmlgreeklish\r\n\r\n" .
Στη συνέχεια του body θα δούμε τα παρακάτω:
--==Multipart_Boundary_xfb728be978e3933c9478450b61e21b72x
Βλέπουμε ότι χρησιμοποιούμε το boundary string, έχοντας πάντα ως πρόθεμα το -- . Έτσι ορίζουμε ότι έχουμε ένα νέο part του body. Αμέσως από κάτω ορίζουμε τα headers:
Content-Type: text/plain;
charset="iso-8859-7"
Content-Transfer-Encoding: 7bit
Λέμε λοιπόν ότι έχουμε το plain text με κωδικοποίηση iso-8859-7 (Ελληνικά), και παρακάτω τοποθετούμε το κείμενό μας σε Ελληνικά και greeklish.
Ελληνικά

test


Greeklish

test
Αντίστοιχα παρακάτω βάζουμε το html part:
--==Multipart_Boundary_xfb728be978e3933c9478450b61e21b72x
Content-Type: text/html; charset="iso-8859-7"
Content-Transfer-Encoding: 7bit

<html>
<body>
<p><b>Ελληνικά</b><br><Br>test<br><BR><Br><b>Greeklish</b><br><Br>test</p>
</body>
</html>
Τέλος πρέπει να πούμε που τελειώνει το τελευταίο part του μηνύματος μας. Αυτό γίνεται εισάγωντας άλλη μια φορά το boundary string, αυτή τη φορά όμως μετά από αυτό βάζουμε τα -- , σαν να κλείνουμε ένα tag:
--==Multipart_Boundary_xfb728be978e3933c9478450b61e21b72x--
Το script αυτό με λίγη τροποποίηση μπορείτε να το αξιοποιησετε με διάφορους τρόπους, με λίγη φαντασία πάντα.
Ολοκληρωμένο το αρχείο το τοποθετώ και σαν attachment.
Συνημμένα
greeklish.zip
(2.14 KiB) Μεταφορτώθηκε 640 φορές

Άβαταρ μέλους
cherouvim
Script Master
Δημοσιεύσεις: 3137
Εγγραφή: 13 Ιούλ 2005 22:56
Τοποθεσία: Athens, Greece
Επικοινωνία:

Multipart email form με ελληνικά και greeklish

Δημοσίευση από cherouvim » 20 Αύγ 2005 10:26

Μπράβο.

Στο 2ο κομμάτι κώδικα μπορείς να χρησημοποιείς την shorthand έκδοση του if:

Κώδικας: Επιλογή όλων

$text = isset&#40;$_POST&#91;'text'&#93;&#41; ? $_POST&#91;'text'&#93; &#58; "";
Για το error handling μπορείς να βελτιώσεις την κατάσταση κάνοντας το εξής κάθε φορά που παίζει error:

Κώδικας: Επιλογή όλων

$errors&#91;&#93;="ΔΕΝ ΕΧΕΤΕ ΔΙΕΥΘΥΝΣΗ ΑΠΟΣΤΟΛΕΑ";
και

Κώδικας: Επιλογή όλων

$errors&#91;&#93;="ΔΕΝ ΕΙΣΑΓΕΙ ΚΕΙΜΕΝΟ";
όταν έρθει η ώρα κάνεις:

Κώδικας: Επιλογή όλων

if &#40;count&#40;$errors&#41;>0&#41;
foreach &#40;$errors as $error&#41;
echo "<strong>$error</strong><br/>";
Οπότε και γνωρίζεις πόσα errors είχες, αλλά και γλιτώνεις το $error=1; (που καλύτερα να ήταν $error++ για να γνωρίζεις πόσα errors είχες).
Πρόσεξε και την χρήση <strong> αντί για <b> :)

Άβαταρ μέλους
mrpc
WebDev Moderator
Δημοσιεύσεις: 3393
Εγγραφή: 03 Μάιος 2000 03:00
Τοποθεσία: Εξάρχεια
Επικοινωνία:

Multipart email form με ελληνικά και greeklish

Δημοσίευση από mrpc » 20 Αύγ 2005 11:35

Σωστός! Thanks!
Φυσικά το να χρησιμοποιείς array για το error handling είναι πιο σωστό, αλλά όπως είπα τον κώδικα τον έγραψα πολύ γρήγορα. Στην αρχή δεν είχα καθόλου error handling, απλά ένα if για να δω αν είχε εισαχθεί κείμενο, μετά με copy - paste έκανα όλο το υπόλοιπο.
Αυτό που λες είναι όμως ο σωστός τρόπος.

Άβαταρ μέλους
cordis
Administrator, [F|H]ounder, [C|S]EO
Δημοσιεύσεις: 27622
Εγγραφή: 09 Οκτ 1999 03:00
Τοποθεσία: Greece
Επικοινωνία:

Multipart email form με ελληνικά και greeklish

Δημοσίευση από cordis » 21 Αύγ 2005 14:02

πλάκα έχει.. :P
Δεν απαντάω σε προσωπικά μηνύματα με ερωτήσεις που καλύπτονται από τις ενότητες του forum. Για ο,τι άλλο είμαι εδώ για εσάς.
- follow me @twitter

Απάντηση

Επιστροφή στο “PHP τα δικά μας scripts”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 0 επισκέπτες