sms.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <?php
  2. require_once 'sms.secrets';
  3. define('DEBUG', true);
  4. define('PARAMS', array('to', 'from', 'body', 'is_mms'));
  5. define('PARAMS_MMS', array('url', 'file_name', 'mime_type', 'file_size'));
  6. define('DEFAULT_NUM', '8002221222');
  7. define('MAX_ATTACHMENT_SIZE', 25*(1024*1024));
  8. debug_log('INIT');
  9. use PHPMailer\PHPMailer\PHPMailer;
  10. use PHPMailer\PHPMailer\Exception;
  11. require_once 'PHPMailer/src/Exception.php';
  12. require_once 'PHPMailer/src/PHPMailer.php';
  13. require_once 'PHPMailer/src/SMTP.php';
  14. debug_log('READ');
  15. $raw = @file_get_contents('php://input');
  16. if (!$raw) {
  17. fail('READ');
  18. }
  19. debug_log('JSON');
  20. $data = @json_decode($raw);
  21. if (!$data || !is_object($data)) {
  22. fail('JSON');
  23. }
  24. if (!DEBUG) {
  25. unset($raw);
  26. }
  27. debug_log('FIND');
  28. if (!property_exists($data, 'data') || !is_object($data->{'data'}) ||
  29. !property_exists($data->{'data'}, 'attributes') ||
  30. !is_object($data->{'data'}->{'attributes'})
  31. ) {
  32. fail('FIND');
  33. }
  34. $msg = $data->{'data'}->{'attributes'};
  35. debug_log('PARSE');
  36. foreach (PARAMS as $param) {
  37. if (!property_exists($msg, $param)) {
  38. fail('PARSE: ' . $param);
  39. }
  40. }
  41. $sms = array();
  42. foreach (PARAMS as $param) {
  43. $sms[$param] = $msg->{$param};
  44. }
  45. unset($msg);
  46. cleanNum($sms, 'to');
  47. cleanNum($sms, 'from');
  48. debug_log('FIND_MMS');
  49. if ($sms['is_mms']) {
  50. if (!property_exists($data, 'included') || !is_array($data->{'included'})) {
  51. fail('FIND_MMS');
  52. }
  53. $msg = $data->{'included'};
  54. foreach ($msg as $part) {
  55. if (!property_exists($part, 'attributes') || !is_object($part->{'attributes'})) {
  56. fail('FIND_MMS_PART');
  57. }
  58. $part = $part->{'attributes'};
  59. debug_log('PARSE_MMS');
  60. foreach (PARAMS_MMS as $param) {
  61. if (!property_exists($part, $param)) {
  62. fail('PARSE_MMS: ' . $param);
  63. }
  64. }
  65. $media = array();
  66. foreach (PARAMS_MMS as $param) {
  67. $media[$param] = $part->{$param};
  68. }
  69. $sms['media'][] = $media;
  70. unset($msg);
  71. }
  72. }
  73. if (!DEBUG) {
  74. unset($data);
  75. }
  76. debug_log('MAIL');
  77. $mail = new PHPMailer();
  78. if (DEBUG) {
  79. $mail->SMTPDebug = 2;
  80. }
  81. $mail->setFrom($sms['from'] . '@' . FROM_DOMAIN, 'SMS ' . $sms['from_pretty']);
  82. $mail->addAddress(TO_ADDR, TO_NAME);
  83. $mail->Subject = 'SMS Message ' . $sms['from_pretty'] . ' => ' . $sms['to_pretty'];
  84. $mail->Body = $sms['body'];
  85. $files = array();
  86. foreach ($sms['media'] as $file) {
  87. debug_log('MEDIA');
  88. if ($file['file_size'] < 1 || $file['file_size'] > MAX_ATTACHMENT_SIZE) {
  89. debug_log('FILE SIZE: ' . $file['file_size']);
  90. $mail->Body .= "\nWill not fetch " .
  91. '(' . $file['file_size'] . '/' . MAX_ATTACHMENT_SIZE . '): ' .
  92. $file['url'] . "\n";
  93. continue;
  94. }
  95. $path = download($file['url']);
  96. if (!$path) {
  97. debug_log('DOWNLOAD FAILED: ' . $file['url']);
  98. $mail->Body .= "\nCould not fetch: " . $file['url'] . "\n";
  99. continue;
  100. }
  101. debug_log('ADDING: ' . $path);
  102. $files[] = $path;
  103. $mail->addAttachment($path, $file['file_name'], 'base64', $file['mime_type'], 'attachment');
  104. }
  105. if (!$mail->send()) {
  106. debug_log('Mail error: ' . $mail->ErrorInfo);
  107. fail('MAIL');
  108. }
  109. foreach ($files as $path) {
  110. debug_log('REMOVING: ' . $path);
  111. @unlink($path);
  112. }
  113. unset($mail);
  114. debug_log('CLEANUP');
  115. if (!DEBUG) {
  116. unset($sms);
  117. }
  118. if (DEBUG) {
  119. debug_log('DEBUG');
  120. debug_log(print_r($sms, true));
  121. $file = @tempnam('/var/tmp', 'sms.');
  122. if (!$file) {
  123. fail('STORE_INIT');
  124. }
  125. debug_log('File: ' . $file);
  126. if (!@file_put_contents($file . '.raw', print_r($raw, true))) {
  127. fail('STORE_RAW');
  128. }
  129. if (!@file_put_contents($file . '.decoded', print_r($data, true))) {
  130. fail('STORE_DECODED');
  131. }
  132. if (!@file_put_contents($file, print_r($sms, true))) {
  133. fail('STORE_PARSED');
  134. }
  135. }
  136. function cleanNum(&$sms, $field) {
  137. if (preg_match('/\d*(\d{3})(\d{3})(\d{4})\D*$/', $sms[$field], $matches)) {
  138. $sms[$field] = $matches[1] . $matches[2] . $matches[3];
  139. $sms[$field . '_pretty'] = '(' . $matches[1] . ') ' . $matches[2] . '-' . $matches[3];
  140. } else {
  141. debug_log($field . ' number format error: ' . $sms[$field]);
  142. $sms[$field] = DEFAULT_NUM;
  143. }
  144. }
  145. function download($url) {
  146. $file = @tempnam(sys_get_temp_dir(), 'SMS_media.');
  147. if (!$file) {
  148. return false;
  149. }
  150. $fp = @fopen($file, 'w+');
  151. if (!$fp) {
  152. return false;
  153. }
  154. $ch = curl_init($url);
  155. curl_setopt($ch, CURLOPT_FILE, $fp);
  156. curl_setopt($ch, CURLOPT_SSLVERSION, 'CURL_SSLVERSION_MAX_DEFAULT');
  157. curl_exec($ch);
  158. $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  159. curl_close($ch);
  160. fclose($fp);
  161. if ($code == 200) {
  162. return $file;
  163. } else {
  164. unlink($file);
  165. return false;
  166. }
  167. }
  168. function fail($msg = 'Unknown error', $code = 500) {
  169. http_response_code($code);
  170. echo 'Unable to process request: ' . $msg . "\n";
  171. exit(0);
  172. }
  173. function debug_log($msg) {
  174. if (! DEBUG) {
  175. return;
  176. }
  177. echo $msg . "\n";
  178. }
  179. ?>