mailgun-php: Can't send binary attachments through cURL

Hello, I’ve been trying to send mails with PDF or JPG attachments but it fails in the cURL command formatter because escapeshellarg receives the file binary contents:

Stacktrace:

Symfony\Component\Debug\Exception\FatalErrorException:
Error: escapeshellarg(): Input string contains NULL bytes
at vendor/php-http/message/src/Formatter/CurlCommandFormatter.php:43

CurlCommandFormatter:

$body = $request->getBody();
if ($body->getSize() > 0) {
    if (!$body->isSeekable()) {
        return 'Cant format Request as cUrl command if body stream is not seekable.';
    }

    $command .= sprintf(' --data %s', escapeshellarg($body->__toString()));
    
    $body->rewind();
}

This is how I initialize the attachment parameter:

$param['attachment'] = array();
foreach ($attachments as $attachment) {
    $filename = $attachment['fileName'];
    $fileContent = $attachment['content']; // file_get_contents of PDF file made with wkhtmltopdf
    $tmpPath = '/tmp/' .$filename;
    file_put_contents($tmpPath, $fileContent);
        
    array_push($param['attachment'], array(
        'filePath' => $tmpPath,
        'filename' => $filename,
    ));
}

When the call to escapeshellarg is removed, it works as expected and my files are attached.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 19 (2 by maintainers)

Most upvoted comments

Hi all,

I have tested it and I am unable to replicate the same error. The steps I followed:

$ mkdir test
$ cd test
$ composer require mailgun/mailgun-php php-http/curl-client guzzlehttp/psr7

These are the downloaded vendors:

Using version ^2.4 for mailgun/mailgun-php
Using version ^1.7 for php-http/curl-client
Using version ^1.4 for guzzlehttp/psr7
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 14 installs, 0 updates, 0 removals
  - Installing webmozart/assert (1.2.0): Loading from cache
  - Installing php-http/discovery (1.3.0): Loading from cache
  - Installing symfony/options-resolver (v3.4.3): Loading from cache
  - Installing psr/http-message (1.0.1): Loading from cache
  - Installing php-http/message-factory (v1.0.2): Loading from cache
  - Installing clue/stream-filter (v1.4.0): Loading from cache
  - Installing php-http/message (1.6.0): Loading from cache
  - Installing php-http/promise (v1.0.0): Loading from cache
  - Installing php-http/httplug (v1.1.0): Loading from cache
  - Installing php-http/client-common (1.7.0): Loading from cache
  - Installing php-http/multipart-stream-builder (1.0.0): Loading from cache
  - Installing mailgun/mailgun-php (v2.4.0): Loading from cache
  - Installing php-http/curl-client (v1.7.0): Loading from cache
  - Installing guzzlehttp/psr7 (1.4.2): Loading from cache
php-http/discovery suggests installing puli/composer-plugin (Sets up Puli which is recommended for Discovery to work. Check http://docs.php-http.org/en/latest/discovery.html for more details.)
php-http/message suggests installing zendframework/zend-diactoros (Used with Diactoros Factories)
php-http/message suggests installing slim/slim (Used with Slim Framework PSR-7 implementation)
php-http/client-common suggests installing php-http/logger-plugin (PSR-3 Logger plugin)
php-http/client-common suggests installing php-http/cache-plugin (PSR-6 Cache plugin)
php-http/client-common suggests installing php-http/stopwatch-plugin (Symfony Stopwatch plugin)
Writing lock file
Generating autoload files

Then I added a new test.php file with this content:

<?php

require 'vendor/autoload.php';

use Mailgun\Mailgun;

$params = [
    'from'    => 'noreply@domain.com',
    'to'      => 'me@domain.com',
    'subject' => 'MailGun email with attached files',
    'text'    => 'This email contains 2 attached images and 1 PDF file.',
    'attachment' => [
        [
            'filePath' => 'attachment/php.jpg',
            'filename' => 'php.jpg'
        ],
        [
            'filePath' => 'attachment/symfony.png',
            'filename' => 'symfony.png'
        ],
        [
            'filePath' => 'attachment/pdf-file.pdf',
            'filename' => 'pdf-file.pdf'
        ],
    ],
];

$mg = Mailgun::create('key-xxxxxxxx');
$mg->messages()->send('domain.com', $params);

And when I ran php -f test.php the email was sent as expected. I got it with the same copy and content I set so the whole workflow must be fine. This was delivered on my INBOX:

screen shot 2018-01-17 at 14 09 48

Unless we get a full stack trace where we can see that Mailgun SDK is related then I must assume the issue is not related with Mailgun.

If anyone comes here and had the same issue, I managed to solve it by disabling profiling in the httplugbundle configuration which prevents the ProfileClient to be used and thus prevents the CurlCommandFormatter to be called.

@michaeldk , I’ve got the same problem. Disabling profiling really helped. Thanks for saving a lot of my time.

@michaeldk Thank you for your insights! I wondered how the CurlCommandFormatter got pulled into this. I reported the issue in php-http/message#91.

Hey @DavidGarciaCat 😃

Did you have any time to run some tests?

Thanks!