1: <?php
2:
3: /**
4: * Jyxo PHP Library
5: *
6: * LICENSE
7: *
8: * This source file is subject to the new BSD license that is bundled
9: * with this package in the file license.txt.
10: * It is also available through the world-wide-web at this URL:
11: * https://github.com/jyxo/php/blob/master/license.txt
12: */
13:
14: namespace Jyxo;
15:
16: /**
17: * Class for sending error emails (can be used in register_shutdown_function, etc.)
18: *
19: * @category Jyxo
20: * @package Jyxo\ErrorHandling
21: * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
22: * @license https://github.com/jyxo/php/blob/master/license.txt
23: * @author Jakub Tománek
24: */
25: class ErrorMail
26: {
27: /**
28: * Minimal interval between sending two mails; to prevent from mailserver flooding.
29: *
30: * @var integer
31: */
32: const SEND_INTERVAL = 600;
33:
34: /**
35: * Path to the file with last sending timestamp.
36: *
37: * @var string
38: */
39: private $timerFile;
40:
41: /**
42: * Additional headers.
43: *
44: * @var array
45: */
46: private $headers = array();
47:
48: /**
49: * Mail recipients.
50: *
51: * @var array
52: */
53: private $email = array();
54:
55: /**
56: * Constructor.
57: *
58: * @param string $timerFile Path to the file with last sending timestamp
59: * @param string|array $recipients Recipient(s)
60: * @param string $sender Mail sender
61: */
62: public function __construct($timerFile, $recipients, $sender)
63: {
64: $this->timerFile = $timerFile;
65: $this->email = (array) $recipients;
66: $this->headers[] = 'From: ' . $sender;
67: }
68:
69: /**
70: * Sends the error email.
71: *
72: * @param \Exception $e Caught exception
73: * @param boolean $forceTimer Ignore timer (Always send)
74: */
75: public function send(\Exception $e, $forceTimer = false)
76: {
77: if ($forceTimer || $this->timerOutdated()) {
78: $this->mail($this->createMail($e));
79: file_put_contents($this->timerFile, time());
80: }
81: }
82:
83: /**
84: * Checks if we can send another email right now.
85: *
86: * @return boolean
87: */
88: private function timerOutdated()
89: {
90: $send = true;
91: if (is_file($this->timerFile)) {
92: $contents = file_get_contents($this->timerFile);
93: $next = $contents + self::SEND_INTERVAL;
94: if ($next > time()) {
95: // Next timestamp is in the future
96: $send = false;
97: }
98: }
99: return $send;
100: }
101:
102: /**
103: * Creates an error email from an exception.
104: *
105: * @param \Exception $e Caught exception
106: * @return array
107: */
108: private function createMail(\Exception $e)
109: {
110: $subject = get_class($e);
111: if (!empty($_SERVER['SERVER_NAME'])) {
112: $subject .= ': ' . $_SERVER['SERVER_NAME'];
113: }
114:
115: $data = array(
116: 'Exception' => '[' . $e->getCode() . '] ' . $e->getMessage(),
117: 'File' => $e->getFile() . '@' . $e->getLine(),
118: 'Trace' => $e->getTraceAsString(),
119: 'GET' => count($_GET) ? print_r($_GET, true) : null,
120: 'POST' => count($_POST) ? print_r($_POST, true) : null,
121: 'SERVER' => print_r($_SERVER, true)
122: );
123: // Remove empty GET and POST definitions
124: $data = array_filter($data);
125:
126: $message = '';
127: foreach ($data as $key => $val) {
128: $message .= $key . "\n" . str_repeat('-', strlen($key)) . "\n";
129: $message .= $val . "\n\n";
130: }
131:
132: return array($subject, $message);
133: }
134:
135: /**
136: * Actually sends an email.
137: *
138: * @param array $data Array(subject, body)
139: */
140: private function mail(array $data)
141: {
142: list($subject, $message) = $data;
143: @mail(implode(', ', $this->email), $subject, $message, implode("\r\n", $this->headers));
144: }
145: }
146: