php file upload error

Discussion in 'PHP' started by nura235, Oct 24, 2015.

  1. #1
    Hello DP member,

    I need your assistance in solving the php error.

    <?php
    if( isset($_POST['name']) )
    {
        $to = 'username@mysite.com'; // Replace with your email
        $subject = 'Message from mysite'; // Replace with your subject if you need
        $message = 'Name: ' . $_POST['name'] . "\n" .
                             'Company: ' . $_POST['company']. "\n" .
                             'E-mail: ' . $_POST['email']. "\n" .
                             'Phone: ' . $_POST['phone']. "\n\n" .
                             'Interested in: ' . $_POST['interested']. "\n" .
                             'About project: ' . $_POST['comment']. "\n\n\n";
     
     
      // Get a random 32 bit number.
      $num = md5(time()); 
     
      // Define the main headers.
      $headers = 'From:' . $_POST['name'] . "\r\n";
      $headers .= 'Reply-To:' . $_POST['email'] . "\r\n";
      $headers .= "MIME-Version: 1.0\r\n";
      $headers .= "Content-Type: multipart/mixed; ";
      $headers .= "boundary=$num\r\n";
      $headers .= "--$num\r\n"; 
     
      // Define the message section
        $headers .= "Content-Type: text/plain\r\n";
        $headers .= "Content-Transfer-Encoding:8bit\r\n\n";
        $headers .= "$message\r\n";
        $headers .= "--$num\r\n";
       
        if( isset($_FILES['file']['tmp_name']) )
        {
            // Read the file into a variable
            $file = fopen($_FILES['file']['tmp_name'], 'r');
          $size = $_FILES['file']['size'];
          $content = fread($file, $size);
          $encoded_content = chunk_split(base64_encode($content));       
           
            // Define the attachment section
            $headers .= "Content-Type: ". $_FILES['file']['type'] ."; ";
            $headers .= 'name="' . $_FILES['file']['name'] . '"' . "\r\n";
            $headers .= "Content-Transfer-Encoding: base64\r\n";
            $headers .= "Content-Disposition: attachment; ";
            $headers .= 'filename="' . $_FILES['file']['name'] . '"' . "\r\n\n";
            $headers .= "$encoded_content\r\n";
            $headers .= "--$num--";
        }
           
        // Send email
        mail ($to, $subject, '', $headers);
    }
    ?>
    Code (markup):
    After getting log detail, i came to know there is some error in line 50.

    here is the log detail:
    I tried to remove this single quote in line 50 and it worked for me but instead of attachement in email, I recieved long weird text in the email body.

    I appreciate if any one case help me out from this error.

    Regard
    nura
     
    nura235, Oct 24, 2015 IP
  2. KangBroke

    KangBroke Notable Member

    Messages:
    1,026
    Likes Received:
    59
    Best Answers:
    4
    Trophy Points:
    265
    #2
    You want to avoid multiple newlines in your headers. Stop using \n\n on lines 27 and 44.
     
    KangBroke, Oct 24, 2015 IP
  3. nura235

    nura235 Well-Known Member

    Messages:
    529
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    110
    #3
    Hi,

    I tried using line 27 as
    $headers .= "Content-Transfer-Encoding:8bit\r";
    PHP:
    and 44
    $headers .= 'filename="' . $_FILES['file']['name'] . '"' . "\r";
    
    PHP:
    But still mail not coming, It seems line 50 also need to corrected.
     
    nura235, Oct 24, 2015 IP
  4. KangBroke

    KangBroke Notable Member

    Messages:
    1,026
    Likes Received:
    59
    Best Answers:
    4
    Trophy Points:
    265
    #4
    mail ($to, $subject, $encoded_content, $headers);
     
    KangBroke, Oct 24, 2015 IP
  5. nura235

    nura235 Well-Known Member

    Messages:
    529
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    110
    #5
    still getting below error
    [25-Oct-2015 04:07:38 Etc/GMT] PHP Warning: mail(): Multiple or malformed newlines found in additional_header in /home/folder1/order-process.php on line 50
     
    nura235, Oct 24, 2015 IP
  6. PoPSiCLe

    PoPSiCLe Illustrious Member

    Messages:
    4,623
    Likes Received:
    725
    Best Answers:
    152
    Trophy Points:
    470
    #6
    Stop using \r\n, use PHP_EOL instead.
     
    PoPSiCLe, Oct 24, 2015 IP
  7. nura235

    nura235 Well-Known Member

    Messages:
    529
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    110
    #7
    Hi,
    Any one can convert code php eol as replied by popsicle
     
    nura235, Oct 24, 2015 IP
  8. PoPSiCLe

    PoPSiCLe Illustrious Member

    Messages:
    4,623
    Likes Received:
    725
    Best Answers:
    152
    Trophy Points:
    470
    #8
    You can try this:
    
    <?php
    if (isset($_POST['name'])) {
      $to = 'username@mysite.com'; // Replace with your email
      $subject = 'Message from mysite'; // Replace with your subject if you need
      $message = 'Name: '.$_POST['name'].'<br>
      Company: '.$_POST['company'].'<br>
      E-mail: '.$_POST['email'].'<br>
      Phone: '.$_POST['phone'].'<br>
      Interested in: '.$_POST['interested'].'<br>
      About project: '.$_POST['comment'];
      // Get a random 32 bit number.
      $num = md5(time());
      // Define the main headers.
      $headers = 'From: '.$_POST['name'].PHP_EOL;
      $headers .= 'Reply-To: '.$_POST['email'].PHP_EOL;
      $headers .= 'MIME-Version: 1.0'.PHP_EOL;
      $headers .= 'Content-Type: multipart/mixed'.PHP_EOL;
      $headers .= 'boundary='.$num.PHP_EOL;
      $headers .= '--'.$num.PHP_EOL;
      // Define the message section
      $headers .= 'Content-Type: text/plain'.PHP_EOL;
      $headers .= 'Content-Transfer-Encoding: 8bit'.PHP_EOL;
      $headers .= $message.PHP_EOL;
      $headers .= '--'.$num.PHP_EOL;
       
      if (isset($_FILES['file']['tmp_name'])) {
      // Read the file into a variable
      $file = fopen($_FILES['file']['tmp_name'], 'r');
      $size = $_FILES['file']['size'];
      $content = fread($file, $size);
      $encoded_content = chunk_split(base64_encode($content));   
       
      // Define the attachment section
      $headers .= 'Content-Type: '.$_FILES['file']['type'].PHP_EOL;
      $headers .= 'name="'.$_FILES['file']['name'].'"'.PHP_EOL;
      $headers .= 'Content-Transfer-Encoding: base64'.PHP_EOL;
      $headers .= 'Content-Disposition: attachment'.PHP_EOL;
      $headers .= 'filename="'.$_FILES['file']['name'].'"'.PHP_EOL;
      $headers .= $encoded_content.PHP_EOL;
      $headers .= '--'.$num;
      }
       
      // Send email
      mail ($to, $subject, '', $headers);
    }
    ?>
    
    PHP:
    That is untested, I have no idea if it works or not, but it's the exact same code as the inital one, just removed bugs and errors and such
     
    PoPSiCLe, Oct 25, 2015 IP
  9. nura235

    nura235 Well-Known Member

    Messages:
    529
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    110
    #9
    Thanks for your effort. It is still stuck in line 45 with same error.

     
    nura235, Oct 25, 2015 IP
  10. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #10
    1) stop trying to send the message in your headers, particularly if sending multipart.

    2) STOP using all the $headers .= in a whitespace neutral language.

    3) if you're going to have a divider, define it first.

    4) what's with the newline and the -- in the middle of the boundary declaration? That's just gibberish.

    5) There's nothing REALLY wrong with /r/n, in fact PHP_EOL may in fact NOT return the value e-mails expect. E-mails EXPECT exactly /r/n -- PHP_EOL returns what the server expects, which could be just /r, just /n, /r/n, or even reveresed /n/r, or even some other character!!!

    The problem was you were doing /r/n/n or /n/n or just /r when what you SHOULD have been using was /r/n, and you are adding things to the $header that should be in $message!

    To that end, I usually do this:

    if (!defined('CRLF')) define('CRLF', "\r\n");

    For my newline delimiter in mails.

    Pretty much near as I can tell everything in this thread is a laundry list of how NOT to build a e-mail using PHP... it's pretty well banjaxed. Here, try this:

    <?php
    
    if (isset($_POST['name'])) {
    
    	// check first make sure something else didn't set it
    	if (!defined('CRLF')) define('CRLF', "\r\n");
    
    	$to = 'username@mysite.com';
    	$subject = 'Message from mysite';
    
    	$hash = md5(date('r', time()));
    	$boundary = '--PHP-mixed-' . $hash;
    
    	$headers =
    		'From: ' . $_POST['name'] . CRLF .
    		'Reply-To: ' . $_POST['email'] . CRLF .
    		'X-Mailer: PHP/' . phpversion() . CRLF .
    		'Content-Type: multipart/mixed' . CRLF .
    		'boundary="' . $boundary . '"';
    
    	/*
    		I'm sending this as plaintext not HTML since most GOOD hosts should
    		assume that an HTML e-mail is spam. If you insist on HTML I'd send as
    		both  text/HTML and text/plain using alternative content boundaries
    	*/
    
    	$message =
    		$boundary . $CRLF .
    		'Content-Type: text/plain; charset="utf-8"' . CRLF .
    		'Content-Transfer-Encoding: 8bit' . CRLF .
    		CRLF . // need blank line to indicate end of boundary header!
    		'Name: ' . $_POST['name'] . CRLF .
    		'Company: ' . $_POST['company'] . CRLF .
    		'E-mail: ' . $_POST['email'] . CRLF .
    		'Phone: ' . $_POST['phone'] . CRLF .
    		'Interested in: ' . $_POST['interested'] . CRLF .
    		'About project: ' . $_POST['comment'] . CRLF .
    		CRLF; // extra blank so it's looking for $boundary
    
    	if (isset($_FILES['file']['tmp_name'])) {
    
    		$content = file_get_contents($_FILES['file']['tmp_name']);
    
    		$message .=
    			$boundary . CRLF .
    			'Content-Type: ' . $_FILES['file']['type'] . // NO EOL HERE!!!
    			'; name="' . $_FILES['file']['name'] . '"' . CRLF .
    			'Content-Transfer-Encoding: base64' . CRLF .
    			'Content-Disposition: attachment' . CRLF .
    			CRLF . // need blank line to indicate end of boundary header!
    			chunk_split(base64_encode($content)) . CRLF .
    			CRLF; // another extra blank so it's looking for boundaries
    
    	}
    
    	$message .= $boundary . '--' . CRLF . CRLF;
    	/*
    		remember trailing '--' means end of boundary
    		we need TWO EOL to further confirm end of boundary
    	*/
    
    	mail($to, $subject, $message, $headers);
    
    }
    
    ?>
    Code (markup):
    Might be a typo or two as I'm on the laptop and doped to the gills on painkillers, but that should give you an idea of what was being done wrong. Pay particular attention to the extra empty EOL, the fact that name="" is PART of Content-Type so it should NOT get a CRLF, and how the message AND the attachment are NOT being put into the headers since THEY AREN'T HEADERS!!! That empty '' in your mail() function should have been the giveaway something wasn't kosher.

    E-mails are VERY finicky about carriage returns and linefeeds, PHP_EOL is NOT the answer and you're LUCKY if it works (basically means you're hosting on a modern *nix and not windows, mac or a legacy *nix), and you have to be REALLY sure you're plugging things into the right spots. The headers is NOT where your messages or attachments go!
     
    Last edited: Oct 25, 2015
    deathshadow, Oct 25, 2015 IP
  11. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #11
    Oh, you should probably also sanitize $_POST[] values before plugging them into the header too. Best way to do that is simply to strip out all /r, /n and semi-colons since none of those should appear in any value sent as part of the header. Generally you're safe inside the message since it's unlikely they can guess the random MD5 for the boundaries.
     
    deathshadow, Oct 25, 2015 IP
  12. siteslikecraigslist

    siteslikecraigslist Member

    Messages:
    57
    Likes Received:
    5
    Best Answers:
    0
    Trophy Points:
    48
    #12
    Good suggestions.
     
    siteslikecraigslist, Oct 25, 2015 IP
  13. PoPSiCLe

    PoPSiCLe Illustrious Member

    Messages:
    4,623
    Likes Received:
    725
    Best Answers:
    152
    Trophy Points:
    470
    #13
    Admittedly, @deathshadow's approach is a lot better than mine. I usually don't send files, so I must admit I haven't touched that for ages - I just send links to wherever said files are hiding on my server. Much simpler, and a lot easier to configure. Also, as for the PHP_EOL-bit, that was actually suggested to me when I had trouble with sending/receiving emails sent from a *nix-box. Might have just been that I was lucky it worked?
     
    PoPSiCLe, Oct 25, 2015 IP
  14. alexanderpaul

    alexanderpaul Member

    Messages:
    47
    Likes Received:
    3
    Best Answers:
    0
    Trophy Points:
    48
    #14
    Try sanitize $_POST[] values
     
    alexanderpaul, Oct 25, 2015 IP
    corporatemanager likes this.
  15. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #15
    For those curious, I continued working on the issue with him via PM, and came up with a working demo I tossed into a RAR file here:
    http://www.cutcodedown.com/for_others/nura235/

    There's a live copy running here:
    http://www.cutcodedown.com/for_others/nura235/liveDebug/

    Locked into debug mode, which shows you what WOULD have been sent in the e-mail without actually sending one. If you want to try out the version in the .,rar just follow the instructions in its readme.txt file.

    I went with a class to isolate the scope of the header and message strings being built. I may continue playing with it to automate the creation of the alternative boundary content header since that has to be hardcoded for now, and to integrate my normal method of building forms from an array and handling server-side validation off that same array's data.

    Just thought I'd share in case anyone else has the same question or needs it.

    -- edit --

    .. and YES, I know the formatting of the form is a bit banjaxed in FF and IE, it's thanks to FF's goofy sizing of select, and the lack of type="date" in either of those browsers. Again, demo for functionality, not production code so far as style goes.
     
    deathshadow, Nov 1, 2015 IP