2
\$\begingroup\$

I have an PHP endpoint used to mail me feedback or error logs from my sites here: https://github.com/kaihendry/vanilla-php-feedback-form/blob/master/feedback/feedback.php

<?php
switch ($_SERVER['HTTP_ORIGIN']) {
    case "https://example.com":
        header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
        break;
    default:
        die("Bad origin: " . $_SERVER['HTTP_ORIGIN']);
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
        header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
        header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
    exit;
}
$subject = 'Feedback from ' . $_SERVER['REMOTE_ADDR'] . ' ' . $_SERVER['HTTP_REFERER'];
$input = json_decode(file_get_contents('php://input'), true);
if(empty($input["msg"])) { http_response_code(400); die(); }
$message = json_encode($input, JSON_PRETTY_PRINT) . "\n\n--\n" . json_encode($_SERVER, JSON_PRETTY_PRINT);
if(empty($input["from"]) || !filter_var($input["from"], FILTER_VALIDATE_EMAIL)) {
    mail('me@example.com', $subject, $message);
} else {
    $headers = 'From: ' . $input["from"];
    mail('me@example.com', $subject, $message, $headers);
}
?>

There are a couple of problems:

  1. It's slow. I suspect it's mail(), which is used with ssmtp & AWS SES. It's fast when I comment the mail line out. Can it be backgrounded somehow?
  2. Should I be returning JSON like status OK or not OK if mail() fails? What is best practice?
  3. Is there an easy way of compiling them into a digest or maybe better alternatives to email I may have missed? I'm a bit worried someone can abuse this script using cURL. How can I prevent that sanely?
\$\endgroup\$
  • \$\begingroup\$ my 2 cents: If you plan using json messenging make sure your file are saved with UTF8 without BOM character mode. Short story is; OK is not the same as say OK%20 \$\endgroup\$ – happy Feb 14 '16 at 17:38
  • \$\begingroup\$ updated my answer with 2 and 3 \$\endgroup\$ – nakashu Feb 20 '16 at 17:47
  • \$\begingroup\$ bountyyyyyyy :) \$\endgroup\$ – nakashu Feb 21 '16 at 21:40
1
\$\begingroup\$

1

From looking on the script, seems there is nothing that can be slow except of the mail(). The problem is, it needs to connect with the target mail server and thats often very slow.

mail() got many problems so it is best avoid using it. You can read about it here and here

The best alternative is probably Swiftmailer http://swiftmailer.org/. With that you can solve also your "in background sending" using spool. Your mails will be send after the script finished running.

For the next two questions I would advise to handle your script like an HTTP API.

2

With Spool

you cannot know in real time if sending of your email was an success, as this will happen after your script will terminate.

Without Spool

it could still be faster (or not), but you will know if it was ok right away

What to return depend now on the above

You can use standard response codes, almost for all your scenarios. http_status_codes You don't need to return anything in the body most of the time.

Fail:

  • 400 - Bad Request - when the request is missing $msg, or body json is malformed
  • 401 - Unauthorized - when missing http_origin or not in the list of allowed
  • 405 - Method not allowed - if it is not POST or OPTIONS
  • 409 - Conflict - email sending failed (if not usign spool)

Success:

  • 200 - OK - email send successfully (if not using spool)
  • 202 - Accepted - when everything is ok, but using spool so you don't know if the sending of email was successfull

In an API approach you would be able to call some url to check if your Accepted request was done processing or not, but this is another topic.

3

As I said before, this is basically an API, so all methods how to secure an API apply here. You can study those. If you want to go simple and quick the easier ones are:

  • SSL + Http Basic Auth - simple basic auth when going over https is quite secure
  • SSL + ApiKey in header + Token Auth - basic thing for all API

I would not recommend going without SSL as you can always catch the request and read the keys.

\$\endgroup\$
0
\$\begingroup\$

Never call PHP mail() directly.

At least digest the sorry saga web2mail scripts first.

There are PHP Mail modules that escape line endings correctly.

\$\endgroup\$
  • 2
    \$\begingroup\$ "Never call PHP mail() directly" sounds like good advice, but please elaborate on the danger. \$\endgroup\$ – 200_success Feb 11 '16 at 8:56
  • \$\begingroup\$ @200_success I updated the answer to tell why is that. \$\endgroup\$ – happy Feb 14 '16 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.