How to go around various bug in the Document (File Name) field for uploading

Since scriptcase hasnt done any proper fixes I’ll post the fixes that I had to do before I got it working reasonably…
I have a editable grid called grid_filestorage with a field FILENAME of the type Document (File Name) and a field NR of type integer with a sequence (in ORACLE).

As in my other posts the following errors will occurs if you create such a grid:
1: filenames are not allowed to have any character >=chr(128) nor are various other characters allowed (+ for example) or some characters are converted inproperly so that when a file is uplaoded it can not be downlaoded anymore.

When the code gets generated you get various files among which:
grid_filestorage_doc.php,grid_filestorage_nmutf8.php,grid_filestorage_sajax_js.php

These files contain minor and major bugs which apparently are still not fixed…

The one below is needed to fix the ‘can not upload a file with a + character in it’ complaint one might have.
grid_filestorage_nmutf8.php:


....
    }

    function NM_utf8_urldecode($str)
    {
        if (is_array($str))
        {
            return $str;
        }
        $aRep = array(
                      '&' => '&',
                      '<' => '<',
                      '>' => '>',
                      '"' => '"',
                      "'" => ''',
                      '+' => '&#44',
                      '?' => 'Á',
                      '?' => 'á',

replace that with this:


    }

    function NM_utf8_urldecode($str)
    {
        return rawurldecode($str);      
    }
    
    function NM_utf8_urldecode2($str)
    {
        if (is_array($str))
        {
            return $str;
        }
        $aRep = array(
                      '&' => '&',
                      '<' => '<',
                      '>' => '>',
                      '"' => '"',
                      "'" => ''',
                      '+' => '&#43',
                      '?' => 'Á',

in file grid_filestorage_sajax_js.php there is a more serious bug which still remains in the original sajax code as well.
This one is needed to fix the rest of the + in the filename bug:


....
                function sajax_do_call(func_name, args) {
                        var i, x, n;
                        var uri;
                        var post_data;
                        var target_id;

                        sajax_debug(\"in sajax_do_call()..\" + sajax_request_type + \"/\" + sajax_target_id);
                        target_id = sajax_target_id;
                        if (typeof(sajax_request_type) == \"undefined\" || sajax_request_type == \"\")
                                sajax_request_type = \"GET\";

                        uri = \"" . sajax_url_encode($sajax_remote_uri) . "\";
                        // NM
                        if (-1 != uri.indexOf(\"?\"))
                                uri = uri.substr(0, uri.indexOf(\"?\"));
                        // NM
                        if (sajax_request_type == \"GET\") {

                                if (uri.indexOf(\"?\") == -1)
                                        uri += \"?rs=\" + escape(func_name);
                                else
                                        uri += \"&rs=\" + escape(func_name);
                                uri += \"&rst=\" + escape(sajax_target_id);
                                uri += \"&rsrnd=\" + new Date().getTime();

                                for (i = 0; i < args.length-1; i++)
                                        uri += \"&rsargs[]=\" + escape(args[i]);

                                post_data = null;
                        }
                        else if (sajax_request_type == \"POST\") {
                                post_data = \"rs=\" + escape(func_name);
                                post_data += \"&rst=\" + escape(sajax_target_id);
                                post_data += \"&rsrnd=\" + new Date().getTime();

                                for (i = 0; i < args.length-1; i++)
                                        post_data = post_data + \"&rsargs[]=\" + escape(args[i]);



                        }
                        else {
                                alert(\"Illegal request type: \" + sajax_request_type);
                        }
....
                                if (sajax_request_type == \"POST\") {
                                        x.setRequestHeader(\"Method\", \"POST \" + uri + \" HTTP/1.1\");
                                        x.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");
                                }
....

thje improved code is:


....
                function sajax_do_call(func_name, args) {
                        var i, x, n;
                        var s;
                        var post_data;
                        var target_id;

                        sajax_debug(\"in sajax_do_call()..\" + sajax_request_type + \"/\" + sajax_target_id);
                        target_id = sajax_target_id;
                        if (typeof(sajax_request_type) == \"undefined\" || sajax_request_type == \"\")
                                sajax_request_type = \"GET\";

                        uri = \"" . sajax_url_encode($sajax_remote_uri) . "\";
                        // NM
                        if (-1 != uri.indexOf(\"?\"))
                                uri = uri.substr(0, uri.indexOf(\"?\"));
                        // NM
                        if (sajax_request_type == \"GET\") {

                                if (uri.indexOf(\"?\") == -1)
                                        uri += \"?rs=\" + escape(func_name);
                                else
                                        uri += \"&rs=\" + escape(func_name);
                                uri += \"&rst=\" + escape(sajax_target_id);
                                uri += \"&rsrnd=\" + new Date().getTime();

                                for (i = 0; i < args.length-1; i++)
                                        uri += \"&rsargs[]=\" + escape(args[i]);

                                post_data = null;
                        }
                        else if (sajax_request_type == \"POST\") {
                                post_data = \"rs=\" + escape(func_name);
                                post_data += \"&rst=\" + escape(sajax_target_id);
                                post_data += \"&rsrnd=\" + new Date().getTime();

                                for (i = 0; i < args.length-1; i++){
                                        [/color=RED]s=escape(args[i]);
                                        post_data = post_data + \"&rsargs[]=\" + s.replace(\"+\",\"%2B\");[/color]
                                }
                                        
                        }
                        else {
                                alert(\"Illegal request type: \" + sajax_request_type);
                        }
....
                                if (sajax_request_type == \"POST\") {
                                        x.setRequestHeader(\"Method\", \"POST \" + uri + \" HTTP/1.1\");
                                        x.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded; charset=iso-8859-15\");  //choose your characterset here!
                                }

And here is the rest:
The rest is in grid_filestorage_doc. This one doesnt NOT allow downloads to occur properly. On some browsers downloading wont work. So I had to patch that as well.
The original piece:


...
   if (is_file($trab_doc))  
   { 
       header("Pragma: public", true);
       header("Content-type: application/force-download");
       $sProtectedFilename = str_replace(array(' ', "'", '!', ',', '-', '+'), array('__SC_SPACE__', '__SC_QUOTES__', '__SC_EXCLAMATION__', '__SC_COMMA__', '__SC_MINUS__', '__SC_PLUS__'), $nm_nome_doc);
       $sProtectedFilename = urlencode($sProtectedFilename);
       $sProtectedFilename = str_replace(array('__SC_SPACE__', '__SC_QUOTES__', '__SC_EXCLAMATION__', '__SC_COMMA__', '__SC_MINUS__', '__SC_PLUS__'), array(' ', "'", '!', ',', '-', '+'), $sProtectedFilename);
       if (isset($_SERVER['HTTP_USER_AGENT']) && false !== strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'chrome'))
       {
           header("Content-Disposition: attachment; filename=\"" . $sProtectedFilename . "\"");
       }
       elseif (isset($_SERVER['HTTP_USER_AGENT']) && false !== strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'applewebkit'))
       {
           header("Content-Disposition: attachment; filename=\"" . $nm_nome_doc . "\"");
       }
       elseif (function_exists('NM_utf8_urldecode') && $nm_nome_doc != NM_utf8_urldecode($nm_nome_doc))
       {
           header("Content-Disposition: attachment; filename=\"" . $nm_nome_doc . "\" filename*=UTF-8''" . $sProtectedFilename);
       }
       else
       {
           //header("Content-Disposition: attachment; filename=\"" . $sProtectedFilename . "\"");
           header("Content-Disposition: attachment; filename=\"" . $nm_nome_doc . "\"");
       }
       readfile($trab_doc);
   } 
...

To make it work so that in an ipad automatically the right application is opened, so that it doesnt give an error on ie8 or below and so that as far as I can see all browsers seem to work properly with it (including safari that doesnt seem to work all that well with the standard code).
the adapted code:


...
   if (is_file($trab_doc))  
   { 
//if not applewebkit  so if ie/opera/.. and alike
if (isset($_SERVER['HTTP_USER_AGENT']) && (false == strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'applewebkit'))){
  header("Content-Description: File Transfer");
  header("Expires: 0");
  header("Pragma: public");
  header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
  //       header("Content-Disposition: attachment; filename=\"" . urlencode($nm_nome_doc) . "\" filename*=UTF-8''" . urlencode($nm_nome_doc));
  $sProtectedFilename = str_replace(array(' ', "'", '!', ',', '-', '+'), array('__SC_SPACE__', '__SC_QUOTES__', '__SC_EXCLAMATION__', '__SC_COMMA__', '__SC_MINUS__', '__SC_PLUS__'), $nm_nome_doc);
  $sProtectedFilename = urlencode($sProtectedFilename);
  $sProtectedFilename = str_replace(array('__SC_SPACE__', '__SC_QUOTES__', '__SC_EXCLAMATION__', '__SC_COMMA__', '__SC_MINUS__', '__SC_PLUS__'), array(' ', "'", '!', ',', '-', '+'), $sProtectedFilename);
  if (isset($_SERVER['HTTP_USER_AGENT']) && false !== strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'chrome'))
  {[/color]
         header("Content-Disposition: attachment; filename=\"" . $sProtectedFilename . "\"");
  [/color=RED]}
  elseif (isset($_SERVER['HTTP_USER_AGENT']) && false !== strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'applewebkit'))
  {
         header("Content-Disposition: attachment; filename=\"" . $nm_nome_doc . "\"");
  }
  elseif (function_exists('NM_utf8_urldecode') && $nm_nome_doc != NM_utf8_urldecode($nm_nome_doc))
  {
         header("Content-Disposition: attachment; filename=\"" . $nm_nome_doc . "\" filename*=UTF-8''" . $sProtectedFilename);
  }
  else
  {
         header("Content-Disposition: attachment; filename=\"" . $sProtectedFilename . "\"");
  }
  header('Content-Transfer-Encoding: binary');
  header("Content-Length: ".filesize($trab_doc));
}else{
   $finfo=finfo_open(FILEINFO_MIME_TYPE);
   if (strtolower(substr($filename,-4))=='.eml'){
     echo header("Content-type: message/rfc822");
   }else{
     echo header("Content-type: ".finfo_file($finfo,$trab_doc));
   }
   finfo_close($finfo);
   $sProtectedFilename = str_replace(array(' ', "'", '!', ',', '-', '+'), array('__SC_SPACE__', '__SC_QUOTES__', '__SC_EXCLAMATION__', '__SC_COMMA__', '__SC_MINUS__', '__SC_PLUS__'), $nm_nome_doc);
   $sProtectedFilename = urlencode($sProtectedFilename);
   $sProtectedFilename = str_replace(array('__SC_SPACE__', '__SC_QUOTES__', '__SC_EXCLAMATION__', '__SC_COMMA__', '__SC_MINUS__', '__SC_PLUS__'), array(' ', "'", '!', ',', '-', '+'), $sProtectedFilename);
   if (isset($_SERVER['HTTP_USER_AGENT']) && false !== strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'chrome'))
   {
       header("Content-Disposition: attachment; filename=\"" . $sProtectedFilename . "\"");
   }
   elseif (isset($_SERVER['HTTP_USER_AGENT']) && false !== strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'applewebkit'))
   {
       header("Content-Disposition: attachment; filename=\"" . $nm_nome_doc . "\"");[/color=RED]
   }
   elseif (function_exists('NM_utf8_urldecode') && $nm_nome_doc != NM_utf8_urldecode($nm_nome_doc))
   {
       header("Content-Disposition: attachment; filename=\"" . $nm_nome_doc . "\" filename*=UTF-8''" . $sProtectedFilename);
   }
   else
   {
       header("Content-Disposition: attachment; filename=\"" . $sProtectedFilename . "\"");
   }
}
       readfile($trab_doc);
  }
...

Have fun fixing it…

In this version it is still not possible to store filenames with a character >=chr(128) so be aware that you need to convert those characters from and to utf8 properly als if you want to store those types of filenames.

To delete a file for sure when you delete it from your database add the folowing (change where you need it) code to your OnAfterDelete event:


$tmpFilename={FILENAME};
//if it starts with c:/uniserver then it is probably a temp dir otherwise it would just be a filename
if (substr(strtolower($tmpFilename),0,13)=='c:/uniserver/'){
	$tmpArray=explode('/',$tmpFilename);
	$tmpFilename=array_pop($tmpArray);		//popoff the last of the array
	//now remove the sc_6ffe6419_ which is 12 long
	$tmpFilename=substr($tmpFilename,12);
}
//echo $_SESSION['scriptcase']['grid_filestorage']['glo_nm_path_doc'].'<br>';
//echo [sc_upload_folder].'<br>';
//echo $tmpFilename."<br>";
//echo $_SESSION['scriptcase']['grid_filestorage']['glo_nm_path_doc'].[sc_upload_folder].$tmpFilename.'<br>';
if (file_exists($_SESSION['scriptcase']['grid_filestorage']['glo_nm_path_doc'].[sc_upload_folder].$tmpFilename)){
	unlink($_SESSION['scriptcase']['grid_filestorage']['glo_nm_path_doc'].[sc_upload_folder].$tmpFilename);
};

Only one reaction: John/Bartho when are you going to solve these issues?

Hello,

As I’ve said before, this problem has already been passed on to our developers.
Therefore, the solution will be when they release corrections and they are tested.
And then, will be available for update.

We’re working on it, I ask that you wait one or two updates.
Because we are currently working on the next version and other fixes.

[QUOTE=John L. Santos;21542]Hello,

As I’ve said before, this problem has already been passed on to our developers.
Therefore, the solution will be when they release corrections and they are tested.
And then, will be available for update.

We’re working on it, I ask that you wait one or two updates.
Because we are currently working on the next version and other fixes.[/QUOTE]

I don’t want to offend you. But this issue is very old and yes we know that you wrote that you where working on this. But this bug is very important to us, and your last reaction was months ago. And actually with all the information of rr the issue could be solved quick. But it’s good to know that you are still working on this.

Another version?

I ask you to wait until next week I’ll review all this forum and give a better answer to your problems.

Do you need my application to test it yourself?? I’m happy to send it to you so that you test it. The application is a pretty basic application…