SimpleMailer.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Mail
  17. * @subpackage Demos
  18. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /**
  22. * @see Zend_Loader
  23. */
  24. require_once 'Zend/Loader.php';
  25. /**
  26. * A simple web-mailer based on Zend_Mail_Storage classes.
  27. *
  28. * This simple mailer demonstrates the most important features of the mail reading classes. You can
  29. * use the test mbox and maildir files or a Pop3 or Imap server. It's meant to be run in a web enviroment
  30. * and CLI is not supported. Copy the files to a directory in your webroot and make sure Zend Framework
  31. * is in your include path (including incubator!).
  32. *
  33. * SSL and TLS are supported by Zend_Mail_Storage_[Pop3|Imap], but not shown here). You'd need to add
  34. * 'ssl' => 'SSL'
  35. * or
  36. * 'ssl' => 'TLS'
  37. * if you want to use ssl support.
  38. *
  39. * Because of problems with Windows filenames (maildir needs : in filenames) the maildir folder is in a tar.
  40. * Untar maildir.tar in maildir/ to test maildir support (won't work on Windows).
  41. *
  42. * The structure of the class is very simple. Every method named show...() output HTML, run() inits mail storage
  43. * after login and calls a show method, everything else inits and checks variables and mail storage handler.
  44. *
  45. * @category Zend
  46. * @package Zend_Mail
  47. * @subpackage Demos
  48. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  49. * @license http://framework.zend.com/license/new-bsd New BSD License
  50. */
  51. class Demo_Zend_Mail_SimpleMailer
  52. {
  53. /**
  54. * Mail storage type (mbox, mbox-folder, maildir, maildir-folder, pop3, imap)
  55. *
  56. * @var string
  57. */
  58. private $type;
  59. /**
  60. * Filename, dirname or hostname for current mailstorage
  61. *
  62. * @var string
  63. */
  64. private $param;
  65. /**
  66. * Selected mail message or null if none
  67. *
  68. * @var integer
  69. */
  70. private $messageNum;
  71. /**
  72. * Mail storage handler
  73. *
  74. * @var Zend_Mail_Storage
  75. */
  76. private $mail;
  77. /**
  78. * Query string with current selection for output
  79. *
  80. * @var string
  81. */
  82. private $queryString;
  83. /**
  84. * Don't run run(), needed for auth
  85. *
  86. * @var boolean
  87. */
  88. private $noRun = false;
  89. /**
  90. * Init class for run() and output
  91. *
  92. * @return void
  93. */
  94. function __construct()
  95. {
  96. $this->initVars();
  97. $this->loadClasses();
  98. $this->whitelistParam();
  99. // we use http auth for username and password or mail storage
  100. if (($this->type == 'pop3' || $this->type == 'imap') && !isset($_SERVER['PHP_AUTH_USER'])) {
  101. $this->needAuth();
  102. return;
  103. }
  104. switch ($this->type) {
  105. case 'mbox':
  106. $this->mail = new Zend_Mail_Storage_Mbox(array('filename' => $this->param));
  107. break;
  108. case 'mbox-folder':
  109. $this->mail = new Zend_Mail_Storage_Folder_Mbox(array('dirname' => $this->param));
  110. break;
  111. case 'maildir':
  112. $this->mail = new Zend_Mail_Storage_Maildir(array('dirname' => $this->param));
  113. break;
  114. case 'maildir-folder':
  115. $this->mail = new Zend_Mail_Storage_Folder_Maildir(array('dirname' => $this->param));
  116. break;
  117. case 'pop3':
  118. $this->mail = new Zend_Mail_Storage_Pop3(array('host' => $this->param,
  119. 'user' => $_SERVER['PHP_AUTH_USER'],
  120. 'password' => $_SERVER['PHP_AUTH_PW']));
  121. break;
  122. case 'imap':
  123. $this->mail = new Zend_Mail_Storage_Imap(array('host' => $this->param,
  124. 'user' => $_SERVER['PHP_AUTH_USER'],
  125. 'password' => $_SERVER['PHP_AUTH_PW']));
  126. break;
  127. default:
  128. $this->mail = null;
  129. break;
  130. }
  131. }
  132. /**
  133. * Check parameter and type
  134. *
  135. * @return void
  136. */
  137. function whitelistParam()
  138. {
  139. $whitelist = array('mbox' => array('mbox/INBOX', 'mbox/subfolder/test'),
  140. 'mbox-folder' => array('mbox'),
  141. 'maildir' => array('maildir', 'maildir/.subfolder', 'maildir/.subfolder.test'),
  142. 'maildir-folder' => array('maildir', 'maildir/.subfolder', 'maildir/.subfolder.test'),
  143. 'pop3' => array(),
  144. 'imap' => array());
  145. if ($this->type === null || @$whitelist[$this->type] === array() || @in_array($this->param, $whitelist[$this->type])) {
  146. return;
  147. }
  148. throw new Exception('Unknown type or param not in whitelist');
  149. }
  150. /**
  151. * Load needed classes
  152. *
  153. * @return void
  154. */
  155. function loadClasses()
  156. {
  157. $classname = array('mbox' => 'Zend_Mail_Storage_Mbox',
  158. 'mbox-folder' => 'Zend_Mail_Storage_Folder_Mbox',
  159. 'maildir' => 'Zend_Mail_Storage_Maildir',
  160. 'maildir-folder' => 'Zend_Mail_Storage_Folder_Maildir',
  161. 'pop3' => 'Zend_Mail_Storage_Pop3',
  162. 'imap' => 'Zend_Mail_Storage_Imap');
  163. if (isset($classname[$this->type])) {
  164. Zend_Loader::loadClass($classname[$this->type]);
  165. }
  166. Zend_Loader::loadClass('Zend_Mail_Storage');
  167. }
  168. /**
  169. * Init variables
  170. *
  171. * @return void
  172. */
  173. function initVars()
  174. {
  175. $this->type = isset($_GET['type']) ? $_GET['type'] : null;
  176. $this->param = isset($_GET['param']) ? $_GET['param'] : null;
  177. $this->folder = isset($_GET['folder']) ? $_GET['folder'] : null;
  178. $this->messageNum = isset($_GET['message']) && is_numeric($_GET['message']) ? $_GET['message'] : null;
  179. $this->queryString = http_build_query(array('type' => $this->type,
  180. 'param' => $this->param,
  181. 'folder' => $this->folder));
  182. }
  183. /**
  184. * Send http auth headers, for username and password in pop3 and imap
  185. *
  186. * @return void
  187. */
  188. function needAuth()
  189. {
  190. header("WWW-Authenticate: Basic realm='{$this->type} credentials'");
  191. header('HTTP/1.0 401 Please enter credentials');
  192. $this->noRun = true;
  193. }
  194. /**
  195. * Get data from mail storage and output html
  196. *
  197. * @return void
  198. */
  199. function run()
  200. {
  201. if ($this->noRun) {
  202. return;
  203. }
  204. if ($this->mail instanceof Zend_Mail_Storage_Folder_Interface && $this->folder) {
  205. // could also be done in constructor of $this->mail with parameter 'folder' => '...'
  206. $this->mail->selectFolder($this->folder);
  207. }
  208. $message = null;
  209. try {
  210. if ($this->messageNum) {
  211. $message = $this->mail->getMessage($this->messageNum);
  212. }
  213. } catch(Zend_Mail_Exception $e) {
  214. // ignored, $message is still null and we display the list
  215. }
  216. if (!$this->mail) {
  217. $this->showChooseType();
  218. } else if ($message) {
  219. $this->showMessage($message);
  220. } else {
  221. $this->showList();
  222. }
  223. }
  224. /**
  225. * Output html header
  226. *
  227. * @param string $title page title
  228. * @return void
  229. */
  230. function showHeader($title)
  231. {
  232. echo "<html><head>
  233. <title>{$title}</title>
  234. <style>
  235. table {border: 1px solid black; border-collapse: collapse}
  236. td, th {border: 1px solid black; padding: 3px; text-align: left}
  237. th {text-align: right; background: #eee}
  238. tr.unread td {font-weight: bold}
  239. tr.flagged td {font-style: italic}
  240. tr.new td {color: #800}
  241. .message {white-space: pre; font-family: monospace; padding: 0.5em}
  242. dl dt {font-style: italic; padding: 1em 0; border-top: 1px #888 dashed}
  243. dl dd {padding-bottom: 1em}
  244. dl dt:first-child {border: none; padding-top: 0}
  245. </style>
  246. </head><body><h1>{$title}</h1>";
  247. }
  248. /**
  249. * Output html footer
  250. *
  251. * @return void
  252. */
  253. function showFooter()
  254. {
  255. echo '</body></html>';
  256. }
  257. /**
  258. * Output type selection AKA "login-form"
  259. *
  260. * @return void
  261. */
  262. function showChooseType()
  263. {
  264. $this->showHeader('Choose Type');
  265. echo '<form><label>Mbox file</label><input name="param" value="mbox/INBOX"/>
  266. <input type="hidden" name="type" value="mbox"/><input type="submit"/></form>
  267. <form><label>Mbox folder</label><input name="param" value="mbox"/>
  268. <input type="hidden" name="type" value="mbox-folder"/><input type="submit"/></form>
  269. <form><label>Maildir file</label><input name="param" value="maildir"/>
  270. <input type="hidden" name="type" value="maildir"/><input type="submit"/></form>
  271. <form><label>Maildir folder</label><input name="param" value="maildir"/>
  272. <input type="hidden" name="type" value="maildir-folder"/><input type="submit"/></form>
  273. <form><label>Pop3 Host</label><input name="param" value="localhost"/>
  274. <input type="hidden" name="type" value="pop3"/><input type="submit"/></form>
  275. <form><label>IMAP Host</label><input name="param" value="localhost"/>
  276. <input type="hidden" name="type" value="imap"/><input type="submit"/></form>';
  277. $this->showFooter();
  278. }
  279. /**
  280. * Output mail message
  281. *
  282. * @return void
  283. */
  284. function showMessage($message)
  285. {
  286. try {
  287. $from = $message->from;
  288. } catch(Zend_Mail_Exception $e) {
  289. $from = '(unknown)';
  290. }
  291. try {
  292. $to = $message->to;
  293. } catch(Zend_Mail_Exception $e) {
  294. $to = '(unknown)';
  295. }
  296. try {
  297. $subject = $message->subject;
  298. } catch(Zend_Mail_Exception $e) {
  299. $subject = '(unknown)';
  300. }
  301. $this->showHeader($subject);
  302. echo "<table>
  303. <tr><th>From:</td><td>$from</td></tr>
  304. <tr><th>Subject:</td><td>$subject</td></tr>
  305. <tr><th>To:</td><td>$to</td></tr><tr><td colspan='2' class='message'>";
  306. if ($message->isMultipart()) {
  307. echo '<dl>';
  308. foreach (new RecursiveIteratorIterator($message) as $part) {
  309. echo "<dt>Part with type {$part->contentType}:</dt><dd>";
  310. echo htmlentities($part);
  311. echo '</dd>';
  312. }
  313. echo '</dl>';
  314. } else {
  315. echo htmlentities($message->getContent());
  316. }
  317. echo "</td></tr></table><a href='?{$this->queryString}'>back to list</a>";
  318. if ($this->messageNum > 1) {
  319. echo " - <a href=\"?{$this->queryString}&message=", $this->messageNum - 1, '">prev</a>';
  320. }
  321. if ($this->messageNum < $this->mail->countMessages()) {
  322. echo " - <a href=\"?{$this->queryString}&message=", $this->messageNum + 1, '">next</a>';
  323. }
  324. $this->showFooter();
  325. }
  326. /**
  327. * Output message list
  328. *
  329. * @return void
  330. */
  331. function showList()
  332. {
  333. $this->showHeader('Overview');
  334. echo '<table><tr><td></td><th>From</th><th>To</th><th>Subject</th></tr>';
  335. foreach ($this->mail as $num => $message) {
  336. if ($this->mail->hasFlags) {
  337. $class = array();
  338. if ($message->hasFlag(Zend_Mail_Storage::FLAG_RECENT)) {
  339. $class['unread'] = 'unread';
  340. $class['new'] = 'new';
  341. }
  342. if (!$message->hasFlag(Zend_Mail_Storage::FLAG_SEEN)) {
  343. $class['unread'] = 'unread';
  344. }
  345. if ($message->hasFlag(Zend_Mail_Storage::FLAG_FLAGGED)) {
  346. $class['flagged'] = 'flagged';
  347. }
  348. $class = implode(' ', $class);
  349. echo "<tr class='$class'>";
  350. } else {
  351. echo '<tr>';
  352. }
  353. echo "<td><a href='?{$this->queryString}&message=$num'>read</a></td>";
  354. try {
  355. echo "<td>{$message->from}</td><td>{$message->to}</td><td>{$message->subject}</td>";
  356. } catch(Zend_Mail_Exception $e){
  357. echo '<td><em>error</em></td>';
  358. }
  359. echo '</tr>';
  360. }
  361. echo '</table>';
  362. if ($this->mail instanceof Zend_Mail_Storage_Folder_Interface) {
  363. $this->showFolders();
  364. }
  365. $this->showFooter();
  366. }
  367. /**
  368. * Output folder list
  369. *
  370. * @return void
  371. */
  372. function showFolders()
  373. {
  374. echo "<br><form method='get' action='?{$this->queryString}'><label>Change folder:</label>
  375. <select name='folder'>";
  376. $folders = new RecursiveIteratorIterator($this->mail->getFolders(), RecursiveIteratorIterator::SELF_FIRST);
  377. foreach ($folders as $localName => $folder) {
  378. echo '<option ';
  379. if (!$folder->isSelectable()) {
  380. echo 'disabled="disabled" ';
  381. }
  382. $localName = str_pad('', $folders->getDepth() * 12, '&nbsp;', STR_PAD_LEFT) . $localName;
  383. echo "value='$folder'>$localName</option>";
  384. }
  385. echo "</select><input type='submit' value='change'><input type='hidden' name='param' value='{$this->param}'>
  386. <input type='hidden' name='type' value='{$this->type}'></form>";
  387. }
  388. }
  389. // init and run mailer
  390. $SimpleMailer = new Demo_Zend_Mail_SimpleMailer();
  391. $SimpleMailer->run();