Alle images, wich are stored in the private file system path, are not included in the pdf version generated by wkhtmltopdf.

Is there a way to include these images, without granting the "View private files" permission to anonymous?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

jcnventura’s picture

Status: Active » Closed (works as designed)

No, it's not possible. The only way to access those files is either by having the wkhtmltopdf 'browser' login to the site, or to have it access them locally. Unfortunately, wkhtmltopdf is not allowed to access local files because of security concerns.

john duff’s picture

Hi
I solved the problem like this:
1-Installed and enabled Custom Tokens module (https://www.drupal.org/project/token_custom)
2-Created two tokens:
One called 'session-name' with php code return session_name();
Another called 'session-cookie" with php code return $_COOKIE[session_name()];
3-Add to wkhtmltopdf command line options --cookie [custom:session-name] [custom:session-cookie]
Sometimes you need to erase your browser's cookies.

The same thing could be done in print_pdf_wkhtmltopdf.pages.inc

May I suggest this could be included in the next release ?

Chipie’s picture

Thank you for posting your solution.

john duff’s picture

Ok I found situations where there were two session cookies. As wkhtmltopdf accepts an arbitrary number of cookies, I chose to put them all.
1)Remove Custom Tokens and wkhtmltopdf command line options
2)In the file print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.pages.inc, in function print_pdf_wkhtmltopdf_print_pdf_generate, at line 51 in my version (2.0), make the following change

*************** BEFORE, YOU HAD THIS *****************************************
// use basic http authentication to fetch included CSS, etc
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
$wkhtmltopdf_options .= ' --username ' . check_plain($_SERVER['PHP_AUTH_USER']) . ' --password ' . check_plain($_SERVER['PHP_AUTH_PW']);
}

$descriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'a'));
$cmd = '"' . realpath($pdf_tool[1]) . "\" --page-size $paper_size --orientation $page_orientation --dpi $dpi $wkhtmltopdf_options - -";

*************** NOW, YOU HAVE THAT *****************************************
// use basic http authentication to fetch included CSS, etc
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
$wkhtmltopdf_options .= ' --username ' . check_plain($_SERVER['PHP_AUTH_USER']) . ' --password ' . check_plain($_SERVER['PHP_AUTH_PW']);
}
// HERE IS THE TRICK //
foreach($_COOKIE as $key => $element) {
$wkhtmltopdf_options=$wkhtmltopdf_options.' --cookie '.$key.' '.$element;
}
// DONE
$descriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'a'));
$cmd = '"' . realpath($pdf_tool[1]) . "\" --page-size $paper_size --orientation $page_orientation --dpi $dpi $wkhtmltopdf_options - -";
***************************************************************************

It just sends all cookies to the executable who deals with it. So what you get is the same level of authentication as the current user.

Sorry for publishing this solution in this format, I'm not very familiar with the patch file format commonly used here.

Maybe the module developer could include these 3 lines in the next release ?

Thanks to this page http://www.yourhowto.net/how-to-parse-an-array-in-php/ for teaching me the solution.

john duff’s picture

Version: 7.x-1.x-dev » 7.x-2.0
Status: Closed (works as designed) » Needs review
drenton’s picture

#4 works for me.

drenton’s picture

The cookie value should be url encoded.

  foreach($_COOKIE as $key => $element) {
    $wkhtmltopdf_options .= ' --cookie ' . $key . ' ' . urlencode($element);
  }
BWPanda’s picture

Version: 7.x-2.0 » 7.x-2.x-dev
Component: Miscellaneous » Code
Category: Support request » Task
FileSize
982 bytes

Here's a patch of the code from #4/#7.

Jorrit’s picture

I solved this using the tokenauth module and the following code to manually add a token to all images containing /system/files/.

function ts_misc_node_view_alter(&$build) {
  if ($build['#view_mode'] !== 'print') {
    return;
  }

  if (!isset($build['body'][0]['#markup'])) {
    return;
  }

  $matches = array();
  if (preg_match_all('#src="([^"]+/system/files/[^"]+)"#', $build['body'][0]['#markup'], $matches, PREG_SET_ORDER) > 0) {
    $token = tokenauth_get_token();
    $tokenkey = tokenauth_get_token_key();
    $tokenquery = check_plain($tokenkey .'='. rawurlencode($token));

    foreach ($matches as $match) {
      $url = $match[1];
      if (strpos($url, '?') === false) {
        $url .= '?'. $tokenquery;
      } else {
        $url .= '&'. $tokenquery;
      }
      $build['body'][0]['#markup'] = str_replace($match[1], $url, $build['body'][0]['#markup']);
    }
  }
}

tokenauth must be configured such that 'system/files/*' is allowed to contain tokens.

raveendrab’s picture

Path in #8 seems to solve the problem. However, looks like the patch in #8 is not applied to 7.x-2.1.
Is there any security implications with this patch.

jcnventura’s picture

@raveendrab, Yes. I'm worried that that cookie will sometimes login with permissions to see restricted content.

raveendrab’s picture

What are the alternatives to get private files using wkhtmltopdf.

MariaIoann’s picture

Re-rolled a patch for the latest 7.x-2.2+23-dev version.

djdevin’s picture

This patch uses the same method as dompdf/tcpdf/mpdf which rewrites image paths into local paths and also checks that private images can be viewed.

Support was added for this in #3283295: PrintPDF - Access Control

In addition to this patch you need to add "--enable-local-file-access" to "wkhtmltopdf options" on admin/config/user-interface/print/pdf/wkhtmltopdf