How to extend - class XenForo_ViewPublic_Attachment_View

Search the files for a reroute, I believe the index controller does it. I don't have an IDE up to look.
 
I'm afraid that I'm completely lost now. My goal is to create an add-on that adds one line of code the the following PHP file:

/library/Xenforo/ViewPublic/Attachment/View.php

That line of code is this:

pic001.webp

Wouldn't it be nice if there was a tool in Admin CP that was similar in function to Template Modifications, but was designed to modify PHP files.
 
Slightly off topic, but what exactly are you hoping this add-on would do?

I'm familiar with some of the code in this class, and I'm not entirely convinced that adding that line to that array would actually do anything.
 
Then you don't want to use a new function. You'll need to extend and overwrite renderRaw(). Then do basically the same exact code, just simplify it:

PHP:
     if ($extension === 'pdf') {
       $this->_response->setHeader('Content-type', 'application/pdf', true);
       $this->setDownloadFileName($attachment['filename'], true);

       return new XenForo_FileOutput($this->_params['attachmentFile'])
} else {
   return parent::renderRaw();
}
 
Slightly off topic, but what exactly are you hoping this add-on would do?

I'm familiar with some of the code in this class, and I'm not entirely convinced that adding that line to that array would actually do anything.

Hi Chris,

Currently when we click on a PDF attachment, the browser prompts with a Save File dialog. By adding that one line of code it changes so that clicking a PDF attachment the PDF is displayed in the browser.

I know it works perfect because if I hack the code directly it works.
 
I see. That behaviour is slightly browser and software dependent, though.

In Google Chrome, PDF files automatically open in the browser.

Also, some people may not have a in-browser compatible PDF viewer (SumatraPDF is popular, because it works as a PDF viewer without all the Adobe bloat -- doesn't have in-browser viewing though).

In the case that the PDF viewer has no support for opening in the browser, what happens? Does it gracefully fallback to a download? I believe it does... just worth thinking about that's all.

Looks like @Jeremy has the solution :)
 
Then you don't want to use a new function. You'll need to extend and overwrite renderRaw(). Then do basically the same exact code, just simplify it:

PHP:
     if ($extension === 'pdf') {
       $this->_response->setHeader('Content-type', 'application/pdf', true);
       $this->setDownloadFileName($attachment['filename'], true);

       return new XenForo_FileOutput($this->_params['attachmentFile'])
} else {
   return parent::renderRaw();
}

Thank you, Jeremy.

Which file do I put this code into?
 
I see. That behaviour is slightly browser and software dependent, though.

In Google Chrome, PDF files automatically open in the browser.

Interesting, on my iMac PDF's still bring up the save file dialog box. I assume you're on Windows.
 
Then you don't want to use a new function. You'll need to extend and overwrite renderRaw(). Then do basically the same exact code, just simplify it:

PHP:
     if ($extension === 'pdf') {
       $this->_response->setHeader('Content-type', 'application/pdf', true);
       $this->setDownloadFileName($attachment['filename'], true);

       return new XenForo_FileOutput($this->_params['attachmentFile'])
} else {
   return parent::renderRaw();
}
 
How do I extend and overwrite renderRaw() ??

So far I've only learned how to extend PHP files not functions.
 
The add-on now works!

View.php

PHP:
<?php

class Andy_OpenPDF_ViewPublic_Attachment_View extends XFCP_Andy_OpenPDF_ViewPublic_Attachment_View
{
   public function renderRaw()
   {    
     $attachment = $this->_params['attachment'];
     $extension = XenForo_Helper_File::getFileExtension($attachment['filename']);
    
     if ($extension === 'pdf')
     {
        $this->_response->setHeader('Content-type', 'application/pdf', true);
        $this->setDownloadFileName($attachment['filename'], true);
    
        return new XenForo_FileOutput($this->_params['attachmentFile']);
     } else {
      return parent::renderRaw();
     }
   }
}
?>
 
You have to set these headers, too.
PHP:
$this->_response->setHeader('ETag', $attachment['attach_date'], true);
$this->_response->setHeader('Content-Length', $attachment['file_size'], true);
$this->_response->setHeader('X-Content-Type-Options', 'nosniff');

return new XenForo_FileOutput($this->_params['attachmentFile']);

What you are doing with this addon is this: Before the original renderRaw() function is run, you run your own function.

Your function works like that:
- check if the file is a pdf file. If it is a pdf file, you do your own stuff in the function and return it, after that the original function is not run at all
- if the file is not a pdf file, the original function is executed

Because of that, if you run your own function as there is a pdf file, you have to do all the things the original functions is also doing, and the three setHeader functions are what's missing :)
 
Hi Marcus,

Thank you for going over the code and pointing out that I needed to add those three lines.

View.php

PHP:
<?php

class Andy_OpenPDF_ViewPublic_Attachment_View extends XFCP_Andy_OpenPDF_ViewPublic_Attachment_View
{
   //########################################     
   // the original renderRaw() function is located in library/Xenforo/ViewPublic/Attachment/View.php
   // this renderRaw() will run instead of the original unless we the return parent::renderRaw()
   //########################################
   
   public function renderRaw()
   {     
     $attachment = $this->_params['attachment'];
     $extension = XenForo_Helper_File::getFileExtension($attachment['filename']);
     
     if ($extension === 'pdf')
     {
       $this->_response->setHeader('Content-type', 'application/pdf', true);
       $this->setDownloadFileName($attachment['filename'], true);
       
       $this->_response->setHeader('ETag', $attachment['attach_date'], true);
       $this->_response->setHeader('Content-Length', $attachment['file_size'], true);
       $this->_response->setHeader('X-Content-Type-Options', 'nosniff');         
       
       return new XenForo_FileOutput($this->_params['attachmentFile']);
     } else {
       // run the original renderRaw() function
       return parent::renderRaw();
     }
   }
}
?>
 
Hi Marcus,

You explaining what is happening with this code is extremely appreciated. I had no idea until you took the time to tell me what is happening.

Thank you.
 
The addon is perfect for release. One suggestion and you could learn something with it, too (but it would not help the purpose of this addon). With this small modification, you can setup any filetype to be opened within the browser. To do this, setup an ACP setting:
Code:
OpenAttachments, you name the setting OpenAttachmentsExtensions
Attachments (Attachment Type => ApplicationType):
pdf => application/pdf
abc => image/abcde

The idea is to have an array the user can add in ACP. The array would be displayed in PHP like this:
PHP:
$extensions = array(
  pdf => 'application/pdf',
  abc => 'image/abcde');

PHP:
  public function renderRaw()
{ $attachment = $this->_params['attachment'];$extension = XenForo_Helper_File::getFileExtension($attachment['filename']);

$extensions = XenForo_Application::get('options')->get('OpenAttachmentsExtensions');

if (isset($extensions[$extension]))
{$this->_response->setHeader('Content-type', $extensions[$extension], true);$this->setDownloadFileName($attachment['filename'], true);
$this->_response->setHeader('ETag', $attachment['attach_date'], true);$this->_response->setHeader('Content-Length', $attachment['file_size'], true);$this->_response->setHeader('X-Content-Type-Options', 'nosniff');

return new XenForo_FileOutput($this->_params['attachmentFile']);
} else {// run the original renderRaw() functionreturn parent::renderRaw();
}
}


You would just have to change two lines:
1. add: $extensions = XenForo_Application::get('options')->get('OpenAttachmentsExtensions');
2. modify this: $this->_response->setHeader('Content-type', $extensions[$extension], true);

I am no expert for acp settings, but I am pretty sure it can be done very easy.
 
Top Bottom