XF 2.0 Writing images to the server

AndrewSimm

Well-known member
I have a script that I created in PHP and am trying to convert to work within XF2. One area where I am stuck is understanding how XF2 writes files. Basically, I have a web form where the user can select an image. Below is the PHP I currently use. Is there a different way I should be doing this in XF2?

PHP:
       //This is the directory where images will be saved 
        $target = "/home/***/public_html/player/photos/".$player_id."/"; 
        $target = $target . basename( $_FILES['photo']['name']);
        if(!is_dir("/home/***/public_html/player/photos/".$player_id."/")) {
            mkdir("/home/***/public_html/player/photos/".$player_id."/");
        }

        //Writes the photo to the server 
        move_uploaded_file($_FILES['photo']['tmp_name'], $target);
 
As a heads up, unless this is only accessible to 100% trusted users, that code is probably a big security hole. You really need to watch saving to a user-controlled file name as an attacker could just upload a .php file.

However, as a general idea, you would want to use the XF filesystem abstraction. That means you would use methods in XF\Util\File like copyFileToAbstractedPath. The abstracted paths would be something like data://player/photos/1/test.jpg. That would be mapped internally as needed (by default, to the data/ directory, but it could be stored on a different server).

You wouldn't generally write into files outside of data:// and internal-data:// without specific reasons.
 
As a heads up, unless this is only accessible to 100% trusted users, that code is probably a big security hole. You really need to watch saving to a user-controlled file name as an attacker could just upload a .php file.

However, as a general idea, you would want to use the XF filesystem abstraction. That means you would use methods in XF\Util\File like copyFileToAbstractedPath. The abstracted paths would be something like data://player/photos/1/test.jpg. That would be mapped internally as needed (by default, to the data/ directory, but it could be stored on a different server).

You wouldn't generally write into files outside of data:// and internal-data:// without specific reasons.

Thanks, Mike! Yes, only staff can upload these pictures.
 
Thanks, Mike! Yes, only staff can upload these pictures.

I still can't figure this out. I wish there was a guide on how to accomplish some of the more common tasks like uploading files. I've looked at how the method is used in the avatar file, but can't seem to understand how it all ties together. I understand the final solution is probably simple, but in comparison, when I originally wrote my application (free of any platform) I had hundreds of stockoverflow post I could read.

My original script accomplishes uploading via the following format

PHP:
$picture = ($_FILES['photo']['name']);

$target = "/home/***/public_html/player/photos/".$player_id."/";
$target = $target . basename( $_FILES['photo']['name']);
if(!is_dir("/home/***/public_html/player/photos/".$player_id."/")) {
mkdir("/home/***/public_html/player/photos/".$player_id."/");
}

move_uploaded_file($_FILES['photo']['tmp_name'], $target);

In XF2 my action has this

PHP:
$image = $this->filter('upload','str');
$dataFile = 'data://CIS/News/' . $image;
\XF\Util\File::copyFileToAbstractedPath($image, $dataFile);

and I get: ErrorException: fopen(test_14.gif): failed to open stream: No such file or directory in src/XF/Util/File.php at line 86

Any help would be appreciated
 
move_uploaded_file is very similar in concept to File::copyFileToAbstracted path. One moves, one copies, but otherwise they're about getting a file at location X to location Y.

You changed not only that part (which needs to changed), but all of the code that relates to the file you uploaded -- you're no longer accessing an uploaded file at all. XF does also have code to work with uploaded files, but strictly speaking, $_FILES is still accessible and you can still work with that.

If you do want to deal with the upload using XF code, then the request object has a getFile() method that will return a XF\Http\Upload object. (The simplest example of accessing an uploaded file would be in something like XF\Admin\Controller\Style::actionImport.
 
move_uploaded_file is very similar in concept to File::copyFileToAbstracted path. One moves, one copies, but otherwise they're about getting a file at location X to location Y.

You changed not only that part (which needs to changed), but all of the code that relates to the file you uploaded -- you're no longer accessing an uploaded file at all. XF does also have code to work with uploaded files, but strictly speaking, $_FILES is still accessible and you can still work with that.

If you do want to deal with the upload using XF code, then the request object has a getFile() method that will return a XF\Http\Upload object. (The simplest example of accessing an uploaded file would be in something like XF\Admin\Controller\Style::actionImport.

When I dump $_FILES I get nothing. My form should be straightforward, as it's a post with
<xf:upload name="image" accept=".gif,.jpeg,.jpg,.jpe,.png" />

I can get the filename with $upload = $this->filter('image','str'); but I don't get the temp path. (I don't think it uploads).

edit: specifically $_FILES['image']['tmp_name'] is empty, but $image = $this->filter('image','str'); post, therefore the issue is the file doesn't get uploaded.
 
Last edited:
I'm guessing you haven't made the form itself an "upload" type of form. You can do the standard enctype change, but assuming it's an <xf:form> tag, you can add upload="true" instead.
 
Back
Top Bottom