Welcome Guest, Not a member yet? Register   Sign In
Securing download and hiding its source directory
#1

[eluser]JaRoLLz[/eluser]
I have problem like this:

A user has the ability to upload and download a content. When the user upload a content, it's stored in ./contents directory (. refers to, let's say /opt/myproject/contents --> not web accessible). Now, for example the content that was uploaded recently is an image. When that content arrive in the ./contents directory, its name changed to content_image_1.jpg.

The root of the problem now, is that no user may access ./contents directly AND only a certain user may access the content in that directory. To make that happen, I create a method 'get_content($content_id)' in the controller named 'Contents'.

Code:
function get_content($content_id) {

  $this->load->model('UserModel');
  if ($this->UserModel->checkUserValidity($this->session->userdata('login_id'))) {

    $this->load->model('ContentModel');
    $fullpath = $this->ContentModel->getContentFullPath($content_id);

    if (!is_null($fullpath)) {
      $this->load->helper('download');

      $finfo = pathinfo($fullpath);
      force_download('content'.$finfo['extension'],file_get_contents($fullpath));
    }
  }

}

So, when I tried this code:
Code:
<img src="&lt;?php echo site_url('contents/get_content/1') ?&gt;">
that image showed up (content with id 1 is an image named 'content_image_1.jpg').

HOWEVER, it only works with image. Other types of contents (video flv, audio mp3, text pdf) won't show. For other types of contents, the 'showing' mechanism is adjusted accordingly:
1. For video and audio, I use JW Media Player to embed it with a player like controls.
2. For pdf, I just embed it directly. So, if the user has a pdf plugin in his/her browser, the content will show.

IS there anyway to make this work? What kind of change that needs to be done in get_content method, if any?

p.s.: if the file size is too big, PHP throws excp about mem limit exceeded. I want to avoid this too.
#2

[eluser]JaRoLLz[/eluser]
Sorry for double post. I still hit the dead end. I have to compromise the 'no user may access ./contents directly' requirements to make it work. Making the ./contents web accessible make the content viewing works fine for any content type. So, I don't use get_content at all in the mean time.
#3

[eluser]sofbas[/eluser]
Hi,

I had the same issue. The following code works for audio, I haven't tested for other files yet, but it should work for all types of files, as long as the extension is in the mimes config:
Code:
function audio($id)
    {
        $file = $this->file->find($id);
        $file_name = substr(strrchr($file->path, '/'), 1);
        $mime = get_mime_by_extension($file->path);
        header("Content-Type: $mime");
        header('Content-Disposition: attachment; filename="'.$file_name.'"', false);
        
        if ($fh = fopen($file->path, "r")) {
            $fsize = filesize($file->path);
            header("Content-length: $fsize");
            header("Cache-control: private"); //use this to open files directly
            while(!feof($fh)) {
                $buffer = fread($fh, 2048);
                print ($buffer);
            }
            
        }
        fclose ($fh);
    }

[quote author="JaRoLLz" date="1233519235"]
p.s.: if the file size is too big, PHP throws excp about mem limit exceeded. I want to avoid this too.[/quote]

The above code will work as it is buffering the read to 2Mb, which is much less than standard php mem config.

[quote author="JaRoLLz" date="1233519235"]
1. For video and audio, I use JW Media Player to embed it with a player like controls.
[/quote]
I have tested with a flash media player for audio, and that works well too.

Let me know how you go.
#4

[eluser]JaRoLLz[/eluser]
It's not working for me. The mem exceeded excp is gone, but the content don't show. Only image.

For image, I use img src in the view_content_image.php file. But for video:

view_content_video.php
Code:
<h3>&lt;?php echo $contcat ?&gt; &raquo; &lt;?php echo $contname ?&gt;</h3>

&lt;!-- start embed mediaplayer --&gt;
<p id='videoplayer'>Video Content</p>
[removed][removed]
[removed]
var s1 = new SWFObject('&lt;?php echo base_url().'libraries/mediaplayer/player.swf' ?&gt;','player','400','300','9');
s1.addParam('allowfullscreen','true');
s1.addParam('allowscriptaccess','always');
s1.addParam('flashvars','file=&lt;?php
  echo $contsrc; //the source e.g. http://example.com/contents/get_content/10.html
                 //--&gt; means get content id 10
  ?&gt;');
s1.write('videoplayer');
[removed]
&lt;!-- end embed mediaplayer --&gt;
<br>
<b><em>Kontributor</em></b>
<br>
<p>&lt;?php echo $contuser ?&gt;</p>
<b><em>Deskripsi</em></b>
<br>
<p>
    &lt;?php echo $contdesc ?&gt;
</p>

The video cannot 'stream'. I use JW media player library for the web player.
#5

[eluser]sofbas[/eluser]
What happens when you type in http://example.com/contents/get_content/10.html in the web browser?

Does it allow you to download the file? If it does, check to see the file size is what you are expecting. If not, view the contents of the file with a text editor.
#6

[eluser]sofbas[/eluser]
I am not sure what media player I am using, but it is the one that comes with MultiBox from phatfusion.

The resulting HTML Code is:

Code:
&lt;object width="320" height="70" title="MultiBoxMedia" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"&gt;
<param value="http://example.com/assets/js/multibox/files/mp3player.swf" name="movie"/>
<param value="high" name="quality"/>
<param value="TL" name="salign"/>
<param value="noScale" name="scale"/>
<param value="path=http://example.com/students/download/audio/4" name="FlashVars"/>
&lt;embed width="320" height="70" flashvars="path=http://example.com/students/download/audio/4" scale="noScale" salign="TL" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" quality="high" src="http://example.com/assets/js/multibox/files/mp3player.swf"/&gt;
&lt;/object&gt;
#7

[eluser]JaRoLLz[/eluser]
[quote author="sofbas" date="1233574767"]What happens when you type in http://example.com/contents/get_content/10.html in the web browser?

Does it allow you to download the file? If it does, check to see the file size is what you are expecting. If not, view the contents of the file with a text editor.[/quote]

It allows me to download the file. The size is correct. If I access get_content directly like that, the browser pops a save file dialog.
#8

[eluser]sofbas[/eluser]
Hmmm, if you are able to download the video file correctly, then the media player should treat it as if it is a file it can access.

However, double check that the correct mime-type is being sent, I had to change the mime-type for mp3 in the mimes config file as it wasn't being recognised.
#9

[eluser]JaRoLLz[/eluser]
After messing with it for a while, I found a workaround. If I make the get_content method in a controller full of pre-authentication, the web player will not work. However, if I put the get_content method in a php file, making the calling of the method becomes like this:
Code:
http://example.com/get_content.php?file=$file.ext&salt;=$session_random_string
then it works.

Maybe something is wrong in my auth. Nevertheless, the requirements is met.
#10

[eluser]JaRoLLz[/eluser]
CORRECTION:

This is not working
CODEv1
Code:
http://example.com/get_content.php?file=$file.ext&salt;=$session_random_string

But this is working
CODEv2
Code:
http://example.com/get_content.php?file=$file.ext
The above code has no `salt`, which means no random string authentication. I store the random string in the $_SESSION variable and not the CI native session because that get_content.php is outside of CI codebase.

Now, when I call CODEv1 directly from the browser, the file download will start. That is because if I call it directly, I pass the auth. Now, when I access the view content page which contains the JW player that tries to call the CODEv1 above, the content will not be shown because JW player always fail the auth. I know this because when I check my browser cache for downloaded contents, the JW player downloaded content contains a HTML page that shows auth error, but for directly downloaded contents not through JW player, the cache shows the correct content.

The CODEv1 case also applies with the get_content method that I was trying to implement before.

p.s.: Maybe I'm wrong about this, but this is the conclusion I get so far.




Theme © iAndrew 2016 - Forum software by © MyBB