Answers.Body: <p>I solved my problem moving part of my code to twig.</p>
  <p>So final code looks like:</p>
  <p>twig</p>
  <pre><code>{% set asset = entry.asset.one() %}
  {% set file = alias('@assets') ~ '/' ~ asset.getPath %}
  
  {% header 'Accept-Ranges: bytes' %}
  {% header 'Cache-Control: maxage=1' %}
  {% header 'Content-Transfer-Encoding: binary' %}
  {% header 'Content-Type: ' ~ asset.getMimeType %}
  {% header 'Content-disposition: inline; filename=' ~ asset.filename %}
  {% header 'Pragma: public' %}
  
  {% do craft.mymodule.pdf(file) %}
  </code></pre>
  <p>craft variable</p>
  <pre><code>public function pdf(String $file): void
  {
      readfile($file);
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-06-12T17:58:35.193Z
Answers.Text: Huh... really strange.
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-06-10T16:53:10.123Z
Answers.LastActivityDate: 2023-06-10T16:53:10.123Z
Answers.UserDisplayName: Leo Leoncio
Body: <p>This works fine with <code>devMode(true)</code>, but not when false.</p>
  <p>I'm calling it as a craft variable <code>{% do craft.mymodule.pdf(entry) %}</code></p>
  <pre><code>public function pdf(Entry $entry)
  {
      $asset = $entry-&gt;asset-&gt;one();
  
      $fsPath = Craft::getAlias($asset-&gt;getVolume()-&gt;fs-&gt;path);
      $file = $fsPath . '/' . $asset-&gt;getPath();
  
      header('Accept-Ranges: bytes');
      header('Cache-Control: maxage=1');
      header('Content-Length: ' . $asset-&gt;size);
      header('Content-Transfer-Encoding: binary');
      header('Content-Type: ' . $asset-&gt;getMimeType());
      header('Content-disposition: inline; filename=' . basename($asset-&gt;filename));
      header('Pragma: public');
  
      readfile($file);
      exit;
  }
  </code></pre>
  <p>Error message</p>
  <p><a href="https://i.sstatic.net/t5kGc.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/t5kGc.png" alt="enter image description here" /></a></p>
  <p>BTW, nothing in the logs when it fails.</p>
  
Tags: <assets><pdf><headers>
Title: PDF with Content-disposition: inline; only works with devMode ON
ThreadText: # PDF with Content-disposition: inline; only works with devMode ON
  
  (Asked by: username_0 on 2023-06-10)
  
  This works fine with `devMode(true)`, but not when false.
  
  I'm calling it as a craft variable `{% do craft.mymodule.pdf(entry) %}`
  
  ```
  public function pdf(Entry $entry)
  {
      $asset = $entry->asset->one();
  
      $fsPath = Craft::getAlias($asset->getVolume()->fs->path);
      $file = $fsPath . '/' . $asset->getPath();
  
      header('Accept-Ranges: bytes');
      header('Cache-Control: maxage=1');
      header('Content-Length: ' . $asset->size);
      header('Content-Transfer-Encoding: binary');
      header('Content-Type: ' . $asset->getMimeType());
      header('Content-disposition: inline; filename=' . basename($asset->filename));
      header('Pragma: public');
  
      readfile($file);
      exit;
  }
  
  ```
  
  Error message
  
  [![enter image description here](https://i.sstatic.net/t5kGc.png)](https://i.sstatic.net/t5kGc.png)
  
  BTW, nothing in the logs when it fails.
  
  **Tags:** assets, pdf, headers
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_0 on 2023-06-10. Score: 2
  
  I solved my problem moving part of my code to twig.
  
  So final code looks like:
  
  twig
  
  ```
  {% set asset = entry.asset.one() %}
  {% set file = alias('@assets') ~ '/' ~ asset.getPath %}
  
  {% header 'Accept-Ranges: bytes' %}
  {% header 'Cache-Control: maxage=1' %}
  {% header 'Content-Transfer-Encoding: binary' %}
  {% header 'Content-Type: ' ~ asset.getMimeType %}
  {% header 'Content-disposition: inline; filename=' ~ asset.filename %}
  {% header 'Pragma: public' %}
  
  {% do craft.mymodule.pdf(file) %}
  
  ```
  
  craft variable
  
  ```
  public function pdf(String $file): void
  {
      readfile($file);
  }
  
  ```
  
  > **Comments:**
  > **username_1**: Huh... really strange.  
  
  ---
  
  