Can't see my "uploaded file" using Web->receive

1,201 views
Skip to first unread message

Andrew Quan

unread,
Sep 13, 2013, 4:04:46 AM9/13/13
to f3-fra...@googlegroups.com
Hi guys,

I'm trying out Web->receive to upload an image:

//I use method="post" enctype="multipart/form-data" on my form

$f3->set('UPLOADS','uploads/'); 

    \Web::instance()->receive(function($file){
        var_dump($file); //I can see this
        
        if($file['size'] > (2 * 1024 * 1024)) // if bigger than 2 MB
            return false;

    },
        true, // overwrite
        true // rename to UTF-8 save filename
    );


So I think the file is uploaded to my php servers tmp directory but not to my upload directory that I specified before.
I went to the receive function and noticed that the file will only be written when the http verb is PUT, not including POST? https://github.com/bcosca/fatfree/blob/dev/lib/web.php#L164

Am I missing something?

Andrew Quan

unread,
Sep 13, 2013, 4:15:14 AM9/13/13
to f3-fra...@googlegroups.com
I see receive() tries to transfer the file from the tmp to my uploads directory but doesn't work, sigh, and yes, the directory is writeable (checked and have written to it before).

ikkez

unread,
Sep 13, 2013, 4:20:26 AM9/13/13
to f3-fra...@googlegroups.com
try to commend out this line:
https://github.com/bcosca/fatfree/blob/dev/lib/web.php#L189

sometimes this mime-type check it the bad guy that stops the file from moving to your UPLOADs dir.

Andrew Quan

unread,
Sep 13, 2013, 4:25:23 AM9/13/13
to f3-fra...@googlegroups.com
Thanks, its this line:

If I comment it out, it works!

This is returning false:
(!$func || $fw->call($func,array($file)))

Andrew Quan

unread,
Sep 13, 2013, 4:31:25 AM9/13/13
to f3-fra...@googlegroups.com
This returns false: !$func
This returns NULL: ($fw->call($func,array($file)))


On Friday, September 13, 2013 10:20:26 AM UTC+2, ikkez wrote:

Andrew Quan

unread,
Sep 13, 2013, 4:44:30 AM9/13/13
to f3-fra...@googlegroups.com
So if I keep #191, then I can dump $file on the outside but if I comment out #191 then nothing, makes sense as call() "calls" my function past in right?


On Friday, September 13, 2013 10:20:26 AM UTC+2, ikkez wrote:

Andrew Quan

unread,
Sep 13, 2013, 5:00:49 AM9/13/13
to f3-fra...@googlegroups.com
Ahah! Figured it out...


Just gotta switch these two lines around:

(!$func || $fw->call($func,array($file))) &&
move_uploaded_file($file['tmp_name'],$dst);


I think the function call got in the way/diverted the execution path.

move_uploaded_file($file['tmp_name'],$dst) &&
(!$func || $fw->call($func,array($file)));



On Friday, September 13, 2013 10:20:26 AM UTC+2, ikkez wrote:

Andrew Quan

unread,
Sep 13, 2013, 5:11:41 AM9/13/13
to f3-fra...@googlegroups.com
Oh but then returning false in the actual function won't do anything :/


On Friday, September 13, 2013 10:20:26 AM UTC+2, ikkez wrote:

Andrew Quan

unread,
Sep 13, 2013, 5:19:44 AM9/13/13
to f3-fra...@googlegroups.com
Ok ok, so I undid everything and just added this to my callback function:

return true; //after my filesize check


So the example needs to look like this:

$f3->set('UPLOADS','uploads/'); // don't forget to set an Upload directory, and make it writable!

$overwrite = false; // set to true, to overwrite an existing file; Default: false
$slug = true; // rename file to filesystem-friendly version

$web->receive(function($file){
        var_dump($file);
        /* looks like:
          array(5) {
              ["name"] =>     string(19) "csshat_quittung.png"
              ["type"] =>     string(9) "image/png"
              ["tmp_name"] => string(14) "/tmp/php2YS85Q"
              ["error"] =>    int(0)
              ["size"] =>     int(172245)
            }
        */
        // maybe you want to check the file size
        if($file['size'] > (2 * 1024 * 1024)) // if bigger than 2 MB
            return false; // this file is not valid, return false will skip moving it

        // everything went fine, hurray!
        return true; // allows the file to be moved from php tmp dir to your defined upload dir
}, $overwrite, $slug );


On Friday, September 13, 2013 10:20:26 AM UTC+2, ikkez wrote:

ikkez

unread,
Sep 13, 2013, 5:53:44 AM9/13/13
to f3-fra...@googlegroups.com
ah yeah...excellent... i'll add this to the example ;)

Andrew Quan

unread,
Sep 13, 2013, 6:22:28 AM9/13/13
to f3-fra...@googlegroups.com

Hey ikkez,

What do you think about this output for the receive?

                               $out['success']=!$file['error'] &&
$file['type']==$this->mime($file['name']) &&
(!file_exists($dst) || $overwrite) &&
(!$func || $fw->call($func,array($file))) &&
move_uploaded_file($file['tmp_name'],$dst);
if($out['success']) {
$out['upload_url']=$dst;
$out['mime_type']=$file['type'];
$out['filename']=$file['name'];
$tmp_arr = explode('.', $out['filename']);
$out['file_extension']=$tmp_arr[1];
} else {
$out['error']=$file['error'];
}

Andrew Quan

unread,
Sep 13, 2013, 6:28:38 AM9/13/13
to f3-fra...@googlegroups.com
Forgot to unset the temp array after the file_extension:

unset($tmp_arr);


On Friday, September 13, 2013 11:53:44 AM UTC+2, ikkez wrote:

Andrew Quan

unread,
Sep 13, 2013, 6:35:00 AM9/13/13
to f3-fra...@googlegroups.com

So to not break older implementations, you could just add it to the end:

                                $out[$dst]=!$file['error'] &&
$file['type']==$this->mime($file['name']) &&
(!file_exists($dst) || $overwrite) &&
(!$func || $fw->call($func,array($file))) &&
move_uploaded_file($file['tmp_name'],$dst);
$out['success']=!$file['error'] &&
$file['type']==$this->mime($file['name']) &&
(!file_exists($dst) || $overwrite) &&
(!$func || $fw->call($func,array($file))) &&
move_uploaded_file($file['tmp_name'],$dst);
if($out['success']) {
$out['upload_url']=$dst;
$out['mime_type']=$file['type'];
$out['filename']=$file['name'];
$tmp_arr = explode('.', $out['filename']);
$out['file_extension']=$tmp_arr[1];
unset($tmp_arr);
} else {
$out['error']=$file['error'];
}

On Friday, September 13, 2013 11:53:44 AM UTC+2, ikkez wrote:

Andrew Quan

unread,
Sep 13, 2013, 6:36:55 AM9/13/13
to f3-fra...@googlegroups.com
Oops, the first line of the new code would need to be changed to this:

                                $out['success']=$out[$dst];
if($out['success']) {
$out['upload_url']=$dst;
$out['mime_type']=$file['type'];
$out['filename']=$file['name'];
$tmp_arr = explode('.', $out['filename']);
$out['file_extension']=$tmp_arr[1];
unset($tmp_arr);
} else {
$out['error']=$file['error'];
}

Andrew Quan

unread,
Sep 13, 2013, 8:07:33 AM9/13/13
to f3-fra...@googlegroups.com
Oh right...


I would like to do stuff with the file after it is "confirmed uploaded" and so the extra information would be most helpful, this is what I would like to do:


$f3->set('UPLOADS','uploads/');
$overwrite = true;
$slug = true;

$upload_result = $web->receive(function($file){

        if($file['size'] > (2 * 1024 * 1024)) // if bigger than 2 MB
            return false;

        return true;
    },
    $overwrite,
    $slug
);

if ($upload_result['success']) {
  
    echo $upload_result['upload_url'];
    echo $upload_result['file_extension'];
    echo $upload_result['filename'];

    //do stuff, like image editing
}


Right now, with the current code, $upload_result would be:

['uploads/filename.extension' => true]

I can't use that and all the "hard work" could already be done at moment of confirmed upload.

Adding the following would allow me to do the above:

                                $out['success']=$out[$dst];
if($out['success']) {
$out['upload_url']=$dst;
$out['mime_type']=$file['type'];
$out['filename']=$file['name'];
$tmp_arr = explode('.', $out['filename']);
$out['file_extension']=$tmp_arr[1];
unset($tmp_arr);
} else {
$out['error']=$file['error'];
}


I have thought about using the php tmp version but I want to be able to use the version that makes it to my uploads folder which is only done after "return true;".



On Friday, September 13, 2013 1:44:29 PM UTC+2, ikkez wrote:
sorry, i don't get it? what are you trying to do? fixing a non existing problem? ^^

bcosca

unread,
Sep 13, 2013, 8:16:40 AM9/13/13
to f3-fra...@googlegroups.com
You might have missed the fact that there can be several files being uploaded. $out is a multi-dimensional array for this reason.

Andrew Quan

unread,
Sep 13, 2013, 8:30:26 AM9/13/13
to f3-fra...@googlegroups.com
Ok, here's my new version but without legacy support:


                $file_count = 0;
foreach ($_FILES as $item) {
if (is_array($item['name'])) {
// Transpose array
$tmp=array();
foreach ($item as $keyx=>$cols)
foreach ($cols as $keyy=>$valy)
$tmp[$keyy][$keyx]=$valy;
$item=$tmp;
}
else
$item=array($item);
foreach ($item as $file) {
if (empty($file['name']))
continue;
$base=basename($file['name']);
$dst=$dir.
($slug && preg_match('/(.+?)(\.\w+)?$/',$base,$parts)?
($this->slug($parts[1]).
(isset($parts[2])?$parts[2]:'')):$base);
$out[$file_count]['success']=!$file['error'] &&
$file['type']==$this->mime($file['name']) &&
(!file_exists($dst) || $overwrite) &&
(!$func || $fw->call($func,array($file))) &&
move_uploaded_file($file['tmp_name'],$dst);;
if($out[$file_count]['success']) {
$out[$file_count]['upload_url']=$dst;
$out[$file_count]['mime_type']=$file['type'];
$out[$file_count]['filename']=$file['name'];
$tmp_arr = explode('.', $out[$file_count]['filename']);
$out[$file_count]['file_extension']=$tmp_arr[1];
unset($tmp_arr);
} else {
$out[$file_count]['error']=$file['error'];
}
}
$file_count += 1;
}

bcosca

unread,
Sep 13, 2013, 9:00:47 AM9/13/13
to f3-fra...@googlegroups.com
Why would you even bother to track uploads that failed? It's not on the server anyway.

bcosca

unread,
Sep 13, 2013, 9:07:03 AM9/13/13
to f3-fra...@googlegroups.com
The information you're tracking is in the $file argument passed to your lambda function too. Since this is YOUR specific requirement, there's no need to modify the framework code base for this.

Andrew Quan

unread,
Sep 13, 2013, 9:58:51 AM9/13/13
to f3-fra...@googlegroups.com
Good point, ok new version without error:


                $out=array();
$file_count = 0;
foreach ($_FILES as $item) {
if (is_array($item['name'])) {
// Transpose array
$tmp=array();
foreach ($item as $keyx=>$cols)
foreach ($cols as $keyy=>$valy)
$tmp[$keyy][$keyx]=$valy;
$item=$tmp;
}
else
$item=array($item);
foreach ($item as $file) {
if (empty($file['name']))
continue;
$base=basename($file['name']);
$dst=$dir.
($slug && preg_match('/(.+?)(\.\w+)?$/',$base,$parts)?
($this->slug($parts[1]).
(isset($parts[2])?$parts[2]:'')):$base);
$out[$file_count]['success']=!$file['error'] &&
$file['type']==$this->mime($file['name']) &&
(!file_exists($dst) || $overwrite) &&
(!$func || $fw->call($func,array($file))) &&
move_uploaded_file($file['tmp_name'],$dst);
$out[$file_count]['upload_url']=$dst;
$out[$file_count]['mime_type']=$file['type'];
$out[$file_count]['filename']=$file['name'];
$tmp_arr = explode('.', $out[$file_count]['filename']);
$out[$file_count]['file_extension']=$tmp_arr[1];
unset($tmp_arr);
}
$file_count += 1;
}

Side note: I use a $tmp_arr cos some php servers are strict with not allowing this - explode('.', $out[$file_count]['filename'])[1];

Andrew Quan

unread,
Sep 13, 2013, 10:02:13 AM9/13/13
to f3-fra...@googlegroups.com

...but how do I do this in the lambda function?

$img = new Image($file['name'], false, $f3->get('UPLOADS'));

...the file only gets moved to my uploads folder when I "return true;" in the lambda function.

bcosca

unread,
Sep 13, 2013, 10:23:09 AM9/13/13
to f3-fra...@googlegroups.com
foreach (\Web::instance()->receive(,,,) as $file=>$state)
if ($state)
$img = new Image($file,FALSE,$f3->get('UPLOADS');

Andrew Quan

unread,
Sep 13, 2013, 10:45:12 AM9/13/13
to f3-fra...@googlegroups.com
So you basically use the callback for an uploaded files' restrictions as I won't have access to the $file properties in the callback outside of the callback? 

...I guess I could do some string handling on the url returned in the foreach.

                        $web = \Web::instance();
$callback = function($file){

            // maybe you want to check the file size
            if($file['size'] > (3 * 1024 * 1024)) // if bigger than 2 MB
                return false; // this file is not valid, return false will skip moving it

             return true;
        };
$overwrite = true; // set to true, to overwrite an existing file; Default: false
$slug = true; // rename file to filesystem-friendly version
foreach ($web->receive($callback, $overwrite, $slug) as $file=>$state) {
if ($state) {
var_dump($file, $state); //returns fileurl and true

bcosca

unread,
Sep 13, 2013, 11:40:26 AM9/13/13
to f3-fra...@googlegroups.com
Notice that move_uploaded_file is called last in the series. The callback is designed only for custom validation, nothing more. This is the reason it should return TRUE/FALSE only.

Andrew Quan

unread,
Sep 13, 2013, 11:44:12 AM9/13/13
to f3-fra...@googlegroups.com
Yeah, I saw that, that's why I suggested adding more file details to $out but I understand if you want to keep the $out minimal, just thought we could enhance it since the details are right there to be outputted.

bcosca

unread,
Sep 13, 2013, 11:48:47 AM9/13/13
to f3-fra...@googlegroups.com
Use $f3->set() inside the callback.

Andrew Quan

unread,
Sep 13, 2013, 11:59:56 AM9/13/13
to f3-fra...@googlegroups.com
Oh ma gosh, yeah, I think I'm just too use to small units of code having access only to what they're given access to.

Thanks bcosca & ikkez!

RichardG

unread,
Oct 11, 2013, 7:45:00 PM10/11/13
to f3-fra...@googlegroups.com
Thanks for the info.
I got this issue of ZIP file uploads not working.
I got it working by removing the line.

Another option that worked for me is to add:
'zip'=>'application/x-zip-compressed'

bcosca

unread,
Oct 15, 2013, 6:50:52 PM10/15/13
to f3-fra...@googlegroups.com
Fixed in repo

ikkez

unread,
Sep 13, 2013, 7:44:29 AM9/13/13
to f3-fra...@googlegroups.com
sorry, i don't get it? what are you trying to do? fixing a non existing problem? ^^



Am Freitag, 13. September 2013 12:36:55 UTC+2 schrieb Andrew Quan:

ikkez

unread,
Oct 12, 2013, 3:02:55 PM10/12/13
to f3-fra...@googlegroups.com
i even don't know why this mime check is done anyways for uploads.. i mostly got more problems with it, then it solves (especially with ajax uploads) and so i commend out the line for the mime check.
maybe it's better to work with a blacklist here, instead of a whitelist.
Reply all
Reply to author
Forward
0 new messages